/**
 * my-editor.js — VvvebJS 儲存與新增頁面橋接腳本
 * 覆蓋 Vvveb.Builder.saveAjax 與 Vvveb.FileManager 行為，無縫串接到 Flask 後端，並引入精美網頁型暗黑系模態框
 */
(function () {
  "use strict";

  const SLUG = window.VVVEB_PROJECT_SLUG || "";

  // ── Toast 通知 ──────────────────────────────────────────────────
  function showToast(msg, type) {
    const existing = document.getElementById("vvveb-save-toast");
    if (existing) existing.remove();

    const toast = document.createElement("div");
    toast.id = "vvveb-save-toast";
    const bg = type === "error" ? "#7f1d1d" : "#14532d";
    const border = type === "error" ? "#ef444460" : "#22c55e60";
    Object.assign(toast.style, {
      position: "fixed",
      top: "1rem",
      right: "1rem",
      zIndex: "99999",
      background: bg,
      border: "1px solid " + border,
      color: "#fff",
      borderRadius: "8px",
      padding: "0.65rem 1.1rem",
      fontSize: "0.85rem",
      fontFamily: "Inter, system-ui, sans-serif",
      fontWeight: "500",
      boxShadow: "0 4px 20px rgba(0,0,0,0.5)",
      opacity: "0",
      transform: "translateY(-8px)",
      transition: "opacity 0.3s ease, transform 0.3s ease",
      pointerEvents: "none",
    });
    toast.textContent = msg;
    document.body.appendChild(toast);

    requestAnimationFrame(() => {
      toast.style.opacity = "1";
      toast.style.transform = "translateY(0)";
    });
    setTimeout(() => {
      toast.style.opacity = "0";
      toast.style.transform = "translateY(-8px)";
      setTimeout(() => toast.remove(), 350);
    }, 3000);
  }

  // ── 頂級網頁型模態框 (Web-based Custom Dialogs) ──────────────────────
  function showModalPrompt(title, defaultValue, callback) {
    const existing = document.getElementById("vvveb-custom-modal");
    if (existing) existing.remove();

    const overlay = document.createElement("div");
    overlay.id = "vvveb-custom-modal";
    Object.assign(overlay.style, {
      position: "fixed",
      top: "0",
      left: "0",
      width: "100%",
      height: "100%",
      zIndex: "100000",
      background: "rgba(10, 11, 18, 0.65)",
      backdropFilter: "blur(12px)",
      webkitBackdropFilter: "blur(12px)",
      display: "flex",
      alignItems: "center",
      justifyContent: "center",
      opacity: "0",
      transition: "opacity 0.25s ease-out"
    });

    const card = document.createElement("div");
    Object.assign(card.style, {
      background: "rgba(22, 24, 38, 0.95)",
      border: "1px solid rgba(255, 255, 255, 0.08)",
      boxShadow: "0 20px 50px rgba(0, 0, 0, 0.6), 0 0 40px rgba(99, 102, 241, 0.1)",
      borderRadius: "16px",
      width: "420px",
      padding: "2rem",
      color: "#f8fafc",
      fontFamily: "Inter, system-ui, sans-serif",
      transform: "scale(0.95)",
      transition: "transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1)",
      display: "flex",
      flexDirection: "column",
      gap: "1.25rem"
    });

    card.innerHTML = `
      <div style="font-size: 1.15rem; font-weight: 600; color: #fff; display: flex; align-items: center; gap: 0.6rem;">
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#818cf8" stroke-width="2">
          <path d="M11 4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
          <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
        </svg>
        ${title}
      </div>
      <div>
        <input type="text" id="vvveb-modal-input" style="
          width: 100%;
          background: rgba(13, 14, 24, 0.8);
          border: 1px solid rgba(255, 255, 255, 0.1);
          border-radius: 8px;
          padding: 0.65rem 0.9rem;
          color: #fff;
          font-size: 0.9rem;
          outline: none;
          transition: border-color 0.2s, box-shadow 0.2s;
        " />
      </div>
      <div style="display: flex; justify-content: flex-end; gap: 0.75rem; margin-top: 0.5rem;">
        <button id="vvveb-modal-cancel" style="
          background: transparent;
          border: 1px solid rgba(255, 255, 255, 0.1);
          border-radius: 8px;
          padding: 0.55rem 1.1rem;
          color: #94a3b8;
          font-size: 0.85rem;
          font-weight: 500;
          cursor: pointer;
          transition: background 0.2s, color 0.2s;
        ">取消</button>
        <button id="vvveb-modal-confirm" style="
          background: #4f46e5;
          border: none;
          border-radius: 8px;
          padding: 0.55rem 1.25rem;
          color: #fff;
          font-size: 0.85rem;
          font-weight: 600;
          cursor: pointer;
          transition: background 0.2s;
          box-shadow: 0 4px 12px rgba(79, 70, 229, 0.3);
        ">確定</button>
      </div>
    `;

    overlay.appendChild(card);
    document.body.appendChild(overlay);

    const input = card.querySelector("#vvveb-modal-input");
    input.value = defaultValue;
    input.addEventListener("focus", () => {
      input.style.borderColor = "#818cf8";
      input.style.boxShadow = "0 0 12px rgba(129, 140, 248, 0.25)";
    });
    input.addEventListener("blur", () => {
      input.style.borderColor = "rgba(255, 255, 255, 0.1)";
      input.style.boxShadow = "none";
    });

    const cancelBtn = card.querySelector("#vvveb-modal-cancel");
    cancelBtn.addEventListener("mouseover", () => {
      cancelBtn.style.background = "rgba(255, 255, 255, 0.05)";
      cancelBtn.style.color = "#fff";
    });
    cancelBtn.addEventListener("mouseout", () => {
      cancelBtn.style.background = "transparent";
      cancelBtn.style.color = "#94a3b8";
    });

    const confirmBtn = card.querySelector("#vvveb-modal-confirm");
    confirmBtn.addEventListener("mouseover", () => {
      confirmBtn.style.background = "#4338ca";
    });
    confirmBtn.addEventListener("mouseout", () => {
      confirmBtn.style.background = "#4f46e5";
    });

    // Fade in
    setTimeout(() => {
      overlay.style.opacity = "1";
      card.style.transform = "scale(1)";
    }, 10);

    input.focus();
    input.select();

    function close(value) {
      overlay.style.opacity = "0";
      card.style.transform = "scale(0.95)";
      setTimeout(() => {
        overlay.remove();
        if (value !== undefined) {
          const finalVal = value.trim ? value.trim() : value;
          callback(finalVal);
        }
      }, 250);
    }

    cancelBtn.onclick = () => close();
    confirmBtn.onclick = () => close(input.value);
    
    input.onkeydown = (e) => {
      if (e.key === "Enter") {
        close(input.value);
      } else if (e.key === "Escape") {
        close();
      }
    };
  }

  function showModalConfirm(title, message, callback) {
    const existing = document.getElementById("vvveb-custom-modal");
    if (existing) existing.remove();

    const overlay = document.createElement("div");
    overlay.id = "vvveb-custom-modal";
    Object.assign(overlay.style, {
      position: "fixed",
      top: "0",
      left: "0",
      width: "100%",
      height: "100%",
      zIndex: "100000",
      background: "rgba(10, 11, 18, 0.65)",
      backdropFilter: "blur(12px)",
      webkitBackdropFilter: "blur(12px)",
      display: "flex",
      alignItems: "center",
      justifyContent: "center",
      opacity: "0",
      transition: "opacity 0.25s ease-out"
    });

    const card = document.createElement("div");
    Object.assign(card.style, {
      background: "rgba(22, 24, 38, 0.95)",
      border: "1px solid rgba(255, 255, 255, 0.08)",
      boxShadow: "0 20px 50px rgba(0, 0, 0, 0.6), 0 0 40px rgba(239, 68, 68, 0.1)",
      borderRadius: "16px",
      width: "420px",
      padding: "2rem",
      color: "#f8fafc",
      fontFamily: "Inter, system-ui, sans-serif",
      transform: "scale(0.95)",
      transition: "transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1)",
      display: "flex",
      flexDirection: "column",
      gap: "1.25rem"
    });

    card.innerHTML = `
      <div style="font-size: 1.15rem; font-weight: 600; color: #fff; display: flex; align-items: center; gap: 0.6rem;">
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2">
          <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/>
          <line x1="12" y1="9" x2="12" y2="13"/>
          <line x1="12" y1="17" x2="12.01" y2="17"/>
        </svg>
        ${title}
      </div>
      <div style="font-size: 0.9rem; color: #cbd5e1; line-height: 1.5;">
        ${message}
      </div>
      <div style="display: flex; justify-content: flex-end; gap: 0.75rem; margin-top: 0.5rem;">
        <button id="vvveb-modal-cancel" style="
          background: transparent;
          border: 1px solid rgba(255, 255, 255, 0.1);
          border-radius: 8px;
          padding: 0.55rem 1.1rem;
          color: #94a3b8;
          font-size: 0.85rem;
          font-weight: 500;
          cursor: pointer;
          transition: background 0.2s, color 0.2s;
        ">取消</button>
        <button id="vvveb-modal-confirm" style="
          background: #ef4444;
          border: none;
          border-radius: 8px;
          padding: 0.55rem 1.25rem;
          color: #fff;
          font-size: 0.85rem;
          font-weight: 600;
          cursor: pointer;
          transition: background 0.2s;
          box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3);
        ">確定</button>
      </div>
    `;

    overlay.appendChild(card);
    document.body.appendChild(overlay);

    const cancelBtn = card.querySelector("#vvveb-modal-cancel");
    cancelBtn.addEventListener("mouseover", () => {
      cancelBtn.style.background = "rgba(255, 255, 255, 0.05)";
      cancelBtn.style.color = "#fff";
    });
    cancelBtn.addEventListener("mouseout", () => {
      cancelBtn.style.background = "transparent";
      cancelBtn.style.color = "#94a3b8";
    });

    const confirmBtn = card.querySelector("#vvveb-modal-confirm");
    confirmBtn.addEventListener("mouseover", () => {
      confirmBtn.style.background = "#dc2626";
    });
    confirmBtn.addEventListener("mouseout", () => {
      confirmBtn.style.background = "#ef4444";
    });

    // Fade in
    setTimeout(() => {
      overlay.style.opacity = "1";
      card.style.transform = "scale(1)";
    }, 10);

    confirmBtn.focus();

    function close(confirmed) {
      overlay.style.opacity = "0";
      card.style.transform = "scale(0.95)";
      setTimeout(() => {
        overlay.remove();
        if (confirmed) callback();
      }, 250);
    }

    cancelBtn.onclick = () => close(false);
    confirmBtn.onclick = () => close(true);

    const keyHandler = (e) => {
      if (e.key === "Escape") {
        close(false);
        window.removeEventListener("keydown", keyHandler);
      }
    };
    window.addEventListener("keydown", keyHandler);
  }

  // ── 三欄位頁面表單對話框 (頁面名稱 / 檔案名稱 / 資料夾) ────────────
  function showModalPageForm(actionTitle, defaultTitle, defaultFile, defaultFolder, callback) {
    const existing = document.getElementById("vvveb-custom-modal");
    if (existing) existing.remove();

    const overlay = document.createElement("div");
    overlay.id = "vvveb-custom-modal";
    Object.assign(overlay.style, {
      position: "fixed", top: "0", left: "0", width: "100%", height: "100%",
      zIndex: "100000", background: "rgba(10,11,18,0.65)",
      backdropFilter: "blur(12px)", display: "flex",
      alignItems: "center", justifyContent: "center",
      opacity: "0", transition: "opacity 0.25s ease-out"
    });

    const card = document.createElement("div");
    Object.assign(card.style, {
      background: "rgba(22,24,38,0.97)",
      border: "1px solid rgba(255,255,255,0.08)",
      boxShadow: "0 20px 50px rgba(0,0,0,0.6), 0 0 40px rgba(99,102,241,0.1)",
      borderRadius: "16px", width: "460px", padding: "2rem",
      color: "#f8fafc", fontFamily: "Inter, system-ui, sans-serif",
      transform: "scale(0.95)",
      transition: "transform 0.25s cubic-bezier(0.34,1.56,0.64,1)",
      display: "flex", flexDirection: "column", gap: "1.1rem"
    });

    const fieldStyle = `
      width:100%; background:rgba(13,14,24,0.8);
      border:1px solid rgba(255,255,255,0.1); border-radius:8px;
      padding:0.6rem 0.85rem; color:#fff; font-size:0.88rem;
      outline:none; box-sizing:border-box; transition:border-color 0.2s, box-shadow 0.2s;`;
    const labelStyle = `display:block; font-size:0.78rem; color:#94a3b8; margin-bottom:0.3rem; font-weight:500;`;

    card.innerHTML = `
      <div style="font-size:1.1rem; font-weight:600; color:#fff; display:flex; align-items:center; gap:0.55rem;">
        <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#818cf8" stroke-width="2">
          <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
          <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
        </svg>
        ${actionTitle}
      </div>
      <div>
        <label style="${labelStyle}">頁面名稱（顯示用）</label>
        <input id="pf-title" type="text" style="${fieldStyle}" value="${defaultTitle}" placeholder="我的頁面" />
      </div>
      <div>
        <label style="${labelStyle}">檔案名稱（.html 副檔名可省略）</label>
        <input id="pf-file" type="text" style="${fieldStyle}" value="${defaultFile}" placeholder="my-page" />
      </div>
      <div>
        <label style="${labelStyle}">儲存至資料夾（留空則存放於根目錄）</label>
        <input id="pf-folder" type="text" style="${fieldStyle}" value="${defaultFolder}" placeholder="留空 = 根目錄" />
      </div>
      <div style="display:flex; justify-content:flex-end; gap:0.75rem; margin-top:0.4rem;">
        <button id="pf-cancel" style="background:transparent; border:1px solid rgba(255,255,255,0.1); border-radius:8px; padding:0.5rem 1rem; color:#94a3b8; font-size:0.85rem; cursor:pointer; transition:background 0.2s;">取消</button>
        <button id="pf-confirm" style="background:#4f46e5; border:none; border-radius:8px; padding:0.5rem 1.2rem; color:#fff; font-size:0.85rem; font-weight:600; cursor:pointer; box-shadow:0 4px 12px rgba(79,70,229,0.3); transition:background 0.2s;">確定</button>
      </div>`;

    overlay.appendChild(card);
    document.body.appendChild(overlay);

    const titleInput = card.querySelector("#pf-title");
    const fileInput = card.querySelector("#pf-file");
    const folderInput = card.querySelector("#pf-folder");
    const cancelBtn = card.querySelector("#pf-cancel");
    const confirmBtn = card.querySelector("#pf-confirm");

    // Focus style
    [titleInput, fileInput, folderInput].forEach(inp => {
      inp.addEventListener("focus", () => { inp.style.borderColor = "#818cf8"; inp.style.boxShadow = "0 0 10px rgba(129,140,248,0.2)"; });
      inp.addEventListener("blur", () => { inp.style.borderColor = "rgba(255,255,255,0.1)"; inp.style.boxShadow = "none"; });
    });
    cancelBtn.addEventListener("mouseover", () => { cancelBtn.style.background = "rgba(255,255,255,0.06)"; });
    cancelBtn.addEventListener("mouseout", () => { cancelBtn.style.background = "transparent"; });
    confirmBtn.addEventListener("mouseover", () => { confirmBtn.style.background = "#4338ca"; });
    confirmBtn.addEventListener("mouseout", () => { confirmBtn.style.background = "#4f46e5"; });

    // Auto-fill filename from title
    titleInput.addEventListener("input", () => {
      const slug = titleInput.value.trim().toLowerCase()
        .replace(/[^\w\s-]/g, "").replace(/[\s_]+/g, "-").replace(/^-+|-+$/g, "");
      if (slug) fileInput.value = slug;
    });

    setTimeout(() => { overlay.style.opacity = "1"; card.style.transform = "scale(1)"; }, 10);
    titleInput.focus();
    titleInput.select();

    function close(confirmed) {
      overlay.style.opacity = "0";
      card.style.transform = "scale(0.95)";
      setTimeout(() => {
        overlay.remove();
        if (confirmed) {
          callback({ title: titleInput.value.trim(), filename: fileInput.value.trim(), folder: folderInput.value.trim() });
        } else {
          callback(null);
        }
      }, 220);
    }

    cancelBtn.onclick = () => close(false);
    confirmBtn.onclick = () => close(true);
    fileInput.onkeydown = titleInput.onkeydown = folderInput.onkeydown = (e) => {
      if (e.key === "Enter") close(true);
      if (e.key === "Escape") close(false);
    };
  }

  // ── 覆蓋 Vvveb.Builder.saveAjax ──────────────────────────────────
  function patchSaveAjax() {
    if (typeof Vvveb === "undefined" || !Vvveb.Builder) {
      setTimeout(patchSaveAjax, 200);
      return;
    }

    /**
     * VvvebJS 原始簽名: saveAjax(data, saveUrl, callback, error)
     */
    Vvveb.Builder.saveAjax = function (data, saveUrl, callback, error) {
      if (!SLUG) {
        showToast("錯誤：找不到專案識別碼 (slug)", "error");
        if (error) error(new Error("Missing slug"));
        return;
      }

      // 確保 data 為物件並填入專案識別碼
      if (typeof data !== "object" || data === null) {
        data = {};
      }
      data.slug = SLUG;

      // 保留完整相對路徑，不再扁平化處理檔名，以支援子資料夾
      // if (data.file) {
      //   const parts = data.file.split("/");
      //   data.file = parts[parts.length - 1];
      // }

      // 如果不是新增頁面（即一般的儲存頁面），且未帶有 HTML 內容，則動態獲取目前 HTML
      const isNewPage = !!data.startTemplateUrl;
      if (!isNewPage && !data.html) {
        try {
          data.html = Vvveb.Builder.getHtml ? Vvveb.Builder.getHtml() : "";
        } catch (e) {
          console.error("[my-editor] getHtml failed:", e);
        }
      }

      // 顯示儲存中狀態
      const saveBtn = document.querySelector(".save-btn");
      if (saveBtn && !isNewPage) {
        saveBtn.querySelector(".loading")?.classList.remove("d-none");
        saveBtn.querySelector(".button-text")?.classList.add("d-none");
      }

      // 發送 POST 請求至 Flask API
      fetch("/api/save", {
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: new URLSearchParams(data).toString(),
      })
        .then((res) => {
          if (!res.ok) {
            return res.json().then((errData) => {
              throw new Error(errData.error || "伺服器儲存錯誤");
            });
          }
          return res.json();
        })
        .then((resData) => {
          if (isNewPage) {
            // 新增頁面成功：秀出通知並執行 Vvveb 原生 callback 以載入新頁面
            showToast("✓ 成功建立新頁面：" + resData.file);
            if (callback) {
              callback({
                name: resData.name,
                title: resData.title,
                file: resData.file,
                url: resData.url
              });
            }
          } else {
            // 一般儲存成功
            showToast("✓ 已儲存：" + (resData.saved || data.file));
            if (callback) callback(resData);
            // 停用儲存按鈕（直至下一次變更）
            document.querySelectorAll("#top-panel .save-btn").forEach((e) =>
              e.setAttribute("disabled", "true")
            );
          }
        })
        .catch((err) => {
          showToast("儲存失敗：" + err.message, "error");
          if (error) error(err);
        })
        .finally(() => {
          if (saveBtn && !isNewPage) {
            saveBtn.querySelector(".loading")?.classList.add("d-none");
            saveBtn.querySelector(".button-text")?.classList.remove("d-none");
          }
        });
    };

    console.log("[my-editor] Robust Vvveb.Builder.saveAjax patched for slug:", SLUG);
  }

  // ── 覆蓋 Vvveb.FileManager 頁面操作 ──────────────────────────────
  function patchFileManager() {
    if (typeof Vvveb === "undefined" || !Vvveb.FileManager) {
      setTimeout(patchFileManager, 200);
      return;
    }

    // 覆蓋 init 方法以修正 VvvebJS 使用全球廢棄的 `event.target` 導致在某些瀏覽器/嚴格模式下點擊無效的 Bug
    const originalInit = Vvveb.FileManager.init;
    Vvveb.FileManager.init = function (allowedComponents = {}) {
      originalInit.call(this, allowedComponents);

      // 利用 Clone 移除舊有包含 Bug 的匿名字選區接聽器
      const newTree = this.tree.cloneNode(true);
      this.tree.parentNode.replaceChild(newTree, this.tree);
      this.tree = newTree;

      // 綁定符合標準且高度相容 (e.target) 的新接聽器
      this.tree.addEventListener("click", function (e) {
        let element = e.target.closest("a");
        if (element) {
          e.stopImmediatePropagation();
          if (element.classList.contains('view')) return;
          e.preventDefault();
          return false;
        }
      });

      this.tree.addEventListener("click", function (e) {
        let element = e.target.closest(".delete");
        if (element) {
          Vvveb.FileManager.deletePage(element.closest("li"), e);
          e.stopImmediatePropagation();
          e.preventDefault();
          return false;
        }
      });

      this.tree.addEventListener("click", function (e) {
        let element = e.target.closest(".rename");
        if (element) {
          Vvveb.FileManager.renamePage(element.closest("li"), e, false);
          e.stopImmediatePropagation();
          e.preventDefault();
          return false;
        }
      });

      this.tree.addEventListener("click", function (e) {
        let element = e.target.closest(".duplicate");
        if (element) {
          Vvveb.FileManager.renamePage(element.closest("li"), e, true);
          e.stopImmediatePropagation();
          e.preventDefault();
          return false;
        }
      });

      this.tree.addEventListener("click", function (e) {
        let element = e.target.closest("li[data-page] label");
        if (element) {
          let page = element.parentNode.dataset.page;
          if (page) {
            Vvveb.FileManager.loadPage(page);
            e.stopImmediatePropagation();
            e.preventDefault();
            return false;
          }
        }
      });
    };

    // 覆蓋重新命名 / 複製頁面（三欄位對話框：頁面名稱、檔案名稱、儲存至資料夾）
    Vvveb.FileManager.renamePage = function (element, e, duplicate = false) {
      let page = element.dataset;
      const currentTitle = element.querySelector("label > span")?.textContent?.trim() || page.file.replace(".html","");
      const currentFile = page.file.replace(".html","");
      const action = duplicate ? "複製頁面" : "重新命名頁面";

      showModalPageForm(action, currentTitle, currentFile, "", function (formData) {
        if (!formData) return;
        let { title, filename, folder } = formData;
        if (!filename) return;
        if (!filename.endsWith(".html")) filename += ".html";

        const bodyData = {
          slug: SLUG,
          file: page.file,
          newfile: filename,
          title: title,
          folder: folder,
          duplicate: duplicate ? "true" : "false"
        };

        fetch(`/api/save?action=rename`, {
          method: "POST",
          headers: { "Content-Type": "application/x-www-form-urlencoded" },
          body: new URLSearchParams(bodyData).toString()
        })
          .then((res) => {
            if (!res.ok) {
              return res.json().then((err) => {
                throw new Error(err.error || "操作失敗");
              });
            }
            return res.json();
          })
          .then((data) => {
            showToast(`✓ ${data.message}`);
            const baseName = data.name || data.newfile.replace('.html', '');
            const newTitle = data.title || title || baseName;

            if (duplicate) {
              let pageData = Object.assign({}, Vvveb.FileManager.pages[page.page]);
              pageData["file"] = data.newfile;
              pageData["title"] = newTitle;
              pageData["url"] = data.url;
              pageData["name"] = baseName;
              Vvveb.FileManager.addPage(baseName, pageData);
            } else {
              const oldPageKey = page.page;
              Vvveb.FileManager.pages[oldPageKey]["file"] = data.newfile;
              Vvveb.FileManager.pages[oldPageKey]["title"] = newTitle;
              Vvveb.FileManager.pages[oldPageKey]["url"] = data.url;
              Vvveb.FileManager.pages[oldPageKey]["name"] = baseName;

              let link = element.querySelector("a.view");
              if (link) link.setAttribute("href", data.url);

              let span = element.querySelector("label > span") || element.querySelector("span");
              if (span) span.textContent = newTitle;

              element.dataset.file = data.newfile;
              element.dataset.page = baseName;

              Vvveb.FileManager.pages[baseName] = Vvveb.FileManager.pages[oldPageKey];
              if (baseName !== oldPageKey) {
                delete Vvveb.FileManager.pages[oldPageKey];
              }
            }
          })
          .catch((err) => {
            showToast(`操作失敗：${err.message}`, "error");
          });
      });
    };

    // 覆蓋刪除頁面
    Vvveb.FileManager.deletePage = function (element, e) {
      let page = element.dataset;
      if (page.file.toLowerCase() === "index.html") {
        showToast("錯誤：無法刪除主頁 index.html", "error");
        return;
      }

      showModalConfirm("確認刪除頁面", `確定要刪除 "${page.file}" 頁面嗎？此動作將無法復原。`, function () {
        const bodyData = {
          slug: SLUG,
          file: page.file
        };

        fetch(`/api/save?action=delete`, {
          method: "POST",
          headers: { "Content-Type": "application/x-www-form-urlencoded" },
          body: new URLSearchParams(bodyData).toString()
        })
          .then((res) => {
            if (!res.ok) {
              return res.json().then((err) => {
                throw new Error(err.error || "刪除失敗");
              });
            }
            return res.json();
          })
          .then((data) => {
            showToast(`✓ ${data.message}`);
            
            // 從內部 pages 列表中移除
            delete Vvveb.FileManager.pages[page.page];
            element.remove();
            
            // 如果刪除的是目前正在編輯的頁面，切換回第一個頁面
            if (Vvveb.FileManager.currentPage === page.page) {
              let firstPage = Object.keys(Vvveb.FileManager.pages)[0];
              if (firstPage) {
                Vvveb.FileManager.loadPage(firstPage);
              }
            }
          })
          .catch((err) => {
            showToast(`刪除失敗：${err.message}`, "error");
          });
      });
    };

    console.log("[my-editor] Vvveb.FileManager operations patched.");
  }

  // ── 覆蓋 Vvveb.NewSection 防止佈局崩潰 ─────────────────────────────
  function patchNewSection() {
    if (typeof Vvveb === "undefined" || !Vvveb.NewSection) {
      setTimeout(patchNewSection, 200);
      return;
    }

    Vvveb.NewSection.insert = function () {
      let position = 'before';
      let lastSection = Vvveb.Builder.frameBody.querySelector(':scope > footer:last-of-type');
      if (!lastSection) {
        position = 'after';
        lastSection = Vvveb.Builder.frameBody.querySelector(':scope > main:last-of-type') || 
                      Vvveb.Builder.frameBody.querySelector(':scope > section:last-of-type') ||
                      Vvveb.Builder.frameBody.querySelector(':scope > div:last-of-type') ||
                      Vvveb.Builder.frameBody; // 最安全的回退點：整個 body 節點
      }
      
      this.container = generateElements(this.template)[0];
      if (lastSection === Vvveb.Builder.frameBody) {
        Vvveb.Builder.frameBody.appendChild(this.container);
      } else {
        if (position == 'after') {
          lastSection.after(this.container);
        } else {
          lastSection.before(this.container);
        }
      }
      
      return this.container;
    };

    console.log("[my-editor] Vvveb.NewSection.insert patched to prevent layout crashes.");
  }

  // ── 頁面清單樹狀結構 ────────────────────────────────────────────────
  function patchPageTree() {
    if (typeof Vvveb === "undefined" || !Vvveb.FileManager) {
      setTimeout(patchPageTree, 300);
      return;
    }

    // 攔截 addPages — 批次新增後重組樹狀結構
    const origAddPages = Vvveb.FileManager.addPages;
    if (origAddPages) {
      Vvveb.FileManager.addPages = function (pages) {
        origAddPages.call(this, pages);
        setTimeout(buildPageTree, 80);
      };
    }

    // 攔截 addPage — 單筆新增（Rename/Duplicate）後重組
    const origAddPage = Vvveb.FileManager.addPage;
    if (origAddPage) {
      Vvveb.FileManager.addPage = function (name, page, ...rest) {
        const result = origAddPage.call(this, name, page, ...rest);
        setTimeout(buildPageTree, 80);
        return result;
      };
    }

    console.log("[my-editor] Page tree patch ready.");
  }

  function buildPageTree() {
    // 找到頁面清單容器（支援多種可能的 selector）
    const list = (
      document.querySelector("#file-manager .files") ||
      document.querySelector(".file-manager .files") ||
      document.querySelector("#file-manager ul") ||
      (() => {
        const li = document.querySelector("li[data-file]");
        return li ? li.closest("ul") : null;
      })()
    );
    if (!list) return;

    // 取得所有頁面 li（不包含我們建立的 folder-node）
    const allPageItems = [...list.querySelectorAll("li[data-file]:not(.folder-node-item)")];
    if (allPageItems.length === 0) return;

    // 移除舊的資料夾節點（避免重複）
    list.querySelectorAll(".folder-node").forEach(n => n.remove());

    // 分組：根頁面 vs 子資料夾頁面
    const rootItems = [];
    const folderMap = {}; // folderName -> [li]

    allPageItems.forEach(li => {
      const pageKey = li.dataset.page || "";
      if (pageKey.includes("/")) {
        const folderName = pageKey.split("/").slice(0, -1).join("/");
        if (!folderMap[folderName]) folderMap[folderName] = [];
        folderMap[folderName].push(li);
        li.remove(); // 先從扁平清單移除，稍後放進資料夾節點
      } else {
        rootItems.push(li);
      }
    });

    // 每個資料夾建一個折疊節點並加到清單尾端
    for (const folderName in folderMap) {
      const folderNode = createFolderNode(folderName, folderMap[folderName]);
      list.appendChild(folderNode);
    }
  }

  function createFolderNode(folderPath, childItems) {
    const displayName = folderPath.split("/").pop()
      .replace(/-/g, " ")
      .replace(/\b\w/g, c => c.toUpperCase());

    const li = document.createElement("li");
    li.className = "folder-node";
    li.dataset.folder = folderPath;
    li.style.cssText = "list-style:none;";

    li.innerHTML = `
      <div class="folder-header" style="
        display:flex; align-items:center; gap:0.45rem;
        padding:0.35rem 0.6rem; cursor:pointer; border-radius:6px;
        user-select:none; color:inherit;
        transition:background 0.15s;">
        <svg class="chevron" width="12" height="12" viewBox="0 0 24 24"
          fill="none" stroke="currentColor" stroke-width="2.5"
          style="transition:transform 0.2s; flex-shrink:0; opacity:0.6;">
          <polyline points="6 9 12 15 18 9"></polyline>
        </svg>
        <svg width="15" height="15" viewBox="0 0 24 24" fill="#6366f1" style="flex-shrink:0;">
          <path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
        </svg>
        <span style="font-weight:500;">${displayName}</span>
      </div>
      <ul class="folder-children" style="padding-left:1.1rem; margin:0; list-style:none;"></ul>`;

    const childrenUl = li.querySelector(".folder-children");
    childItems.forEach(child => {
      child.classList.add("folder-node-item");
      childrenUl.appendChild(child);
    });

    // 折疊切換
    const header = li.querySelector(".folder-header");
    const chevron = li.querySelector(".chevron");
    let collapsed = false;

    header.addEventListener("mouseenter", () => { header.style.background = "rgba(99,102,241,0.08)"; });
    header.addEventListener("mouseleave", () => { header.style.background = ""; });
    header.addEventListener("click", (e) => {
      if (e.target.closest("li[data-file]")) return;
      collapsed = !collapsed;
      childrenUl.style.display = collapsed ? "none" : "";
      chevron.style.transform = collapsed ? "rotate(-90deg)" : "";
    });

    return li;
  }

  // ── 動態中文化 VvvebJS 元件與區塊 ─────────────────────────────────
  function patchI18n() {
    if (typeof Vvveb === "undefined" || !Vvveb.ComponentsGroup || Object.keys(Vvveb.ComponentsGroup).length === 0) {
      setTimeout(patchI18n, 500);
      return;
    }

    const translateMap = {
      // 分類 (Groups)
      "Grid": "網格系統",
      "Components": "基礎元件",
      "Basic": "基本",
      "Typography": "排版",
      "Media": "媒體",
      "Forms": "表單",
      "Widgets": "小工具",
      "Advanced": "進階",
      "Content": "內容區塊",
      "Layout": "佈局",
      "Blocks": "區塊",
      "Features": "功能特色",
      "Headers": "頁首",
      "Footers": "頁尾",
      "Pricing": "價格表",
      "Testimonials": "客戶評價",
      "Cards": "卡片",
      "Services": "服務",
      "Team": "團隊",
      "About": "關於我們",

      // 元件 (Components)
      "Grid Row": "網格列 (Row)",
      "Grid Column": "網格欄 (Column)",
      "Container": "容器 (Container)",
      "Heading": "標題 (Heading)",
      "Link": "超連結 (Link)",
      "Image": "圖片 (Image)",
      "Video": "影片 (Video)",
      "Paragraph": "段落文字",
      "List": "列表",
      "List item": "列表項目",
      "Button": "按鈕",
      "Button Group": "按鈕群組",
      "Button Toolbar": "按鈕工具列",
      "Form": "表單",
      "Text Input": "文字輸入框",
      "Textarea": "多行文字框",
      "Checkbox": "核取方塊",
      "Radio": "單選按鈕",
      "Select": "下拉選單",
      "Label": "標籤文字",
      "Alert": "警告提示",
      "Badge": "徽章 (Badge)",
      "Card": "卡片 (Card)",
      "Table": "表格",
      "Progress": "進度條",
      "Navbar": "導覽列 (Navbar)",
      "Breadcrumb": "麵包屑 (Breadcrumb)",
      "Pagination": "分頁",
      "Jumbotron": "大型看板",
      "Panel": "面板",
      "Icon": "圖示",
      "Divider": "分隔線",
      "Map": "地圖",
      "Audio": "音訊",
      "File Upload": "檔案上傳",
      "Date Input": "日期輸入框",
      "Password Input": "密碼輸入框",
      "Email Input": "Email 輸入框",

      // 屬性面板 - 標題與一般屬性
      "General": "一般",
      "Id": "ID",
      "Title": "標題 (Title)",
      "Class": "類別 (Class)",
      "Display": "顯示 (Display)",
      "Position": "定位 (Position)",
      "Top": "上",
      "Left": "左",
      "Bottom": "下",
      "Right": "右",
      "Float": "浮動 (Float)",
      "Opacity": "透明度 (Opacity)",
      "Background": "背景 (Background)",
      "Background Color": "背景顏色",
      "Text Color": "文字顏色",
      "Color": "顏色",

      // 排版與字體
      "Font size": "字體大小",
      "Font weight": "字體粗細",
      "Font family": "字體家族",
      "Text align": "文字對齊",
      "Line height": "行高",
      "Letter spacing": "字距",
      "Text decoration": "文字裝飾",
      "Decoration Color": "裝飾顏色",
      "Decoration style": "裝飾樣式",

      // 尺寸與間距
      "Size": "尺寸",
      "Width": "寬度",
      "Height": "高度",
      "Min Width": "最小寬度",
      "Min Height": "最小高度",
      "Max Width": "最大寬度",
      "Max Height": "最大高度",
      "Margin": "外邊距 (Margin)",
      "Padding": "內邊距 (Padding)",

      // 邊框與陰影
      "Border": "邊框 (Border)",
      "Style": "樣式",
      "Radius": "圓角 (Radius)",
      "Radius Top Left": "左上圓角",
      "Radius Top Right": "右上圓角",
      "Radius Bottom Left": "左下圓角",
      "Radius Bottom Right": "右下圓角",
      "Background Image": "背景圖片",
      "Box Shadow": "盒子陰影",
      "Text Shadow": "文字陰影",
      "Filter": "濾鏡",
      "Transform": "變形",
      "Transition": "過渡效果",

      // 選項值
      "Default": "預設",
      "Primary": "主要 (Primary)",
      "Secondary": "次要 (Secondary)",
      "Success": "成功 (Success)",
      "Danger": "危險 (Danger)",
      "Warning": "警告 (Warning)",
      "Info": "資訊 (Info)",
      "Light": "亮色 (Light)",
      "Dark": "暗色 (Dark)",
      "White": "白色",
      "Block": "區塊 (Block)",
      "Inline": "行內 (Inline)",
      "Inline Block": "行內區塊 (Inline Block)",
      "Flex": "彈性 (Flex)",
      "Inline Flex": "行內彈性 (Inline Flex)",
      "Grid": "網格 (Grid)",
      "Static": "靜態 (Static)",
      "Fixed": "固定 (Fixed)",
      "Relative": "相對 (Relative)",
      "Absolute": "絕對 (Absolute)",

      // 裝置響應式顯示
      "Hide based on device screen width": "依裝置螢幕寬度隱藏",
      "Extra small devices": "超小螢幕 (xs)",
      "Small devices": "小螢幕 (sm)",
      "Medium devices": "中螢幕 (md)",
      "Large devices": "大螢幕 (lg)",
      "Xl devices": "超大螢幕 (xl)",
      "Xxl devices": "超超大螢幕 (xxl)",

      // AOS 動畫
      "Animate on scroll": "滾動動畫 (AOS)",
      "Animation type": "動畫類型",
      "Duration": "持續時間",
      "Delay": "延遲",
      "Play animation": "播放動畫",
      "[none]": "[無]",
      "Fade animations": "淡入淡出動畫",
      "Fade": "淡入",
      "Fade Up": "向上淡入",
      "Fade down": "向下淡入",
      "Fade left": "向左淡入",
      "Fade right": "向右淡入",
      "Fade up right": "向右上淡入",
      "Fade up left": "向左上淡入",
      "Fade down right": "向右下淡入",
      "Fade down left": "向左下淡入",
      "Flip animations": "翻轉動畫",
      "Flip Up": "向上翻轉",
      "Flip Down": "向下翻轉",
      "Flip left": "向左翻轉",
      "Flip right": "向右翻轉",
      "Slide animations": "滑動動畫",
      "Slide up": "向上滑動",
      "Slide down": "向下滑動",
      "Slide left": "向左滑動",
      "Slide right": "向右滑動",
      "Zoom animations": "縮放動畫",
      "Zoom in": "放大",
      "Zoom in up": "向上放大",
      "Zoom in down": "向下放大",
      "Zoom in left": "向左放大",
      "Zoom in right": "向右放大",
      "Zoom out": "縮小",
      "Zoom out up": "向上縮小",
      "Zoom out down": "向下縮小",
      "Zoom out left": "向左縮小",
      "Zoom out right": "向右縮小",

      // 連結樣式提示
      "Linked styles": "共用樣式提示"
    };

    const translateText = (text) => {
      if (!text || typeof text !== "string") return text;
      const trimmed = text.trim();
      return translateMap[trimmed] ? translateMap[trimmed] : text;
    };

    // 1. 翻譯 Vvveb 物件內的資料 (供重新渲染時使用)
    if (Vvveb.ComponentsGroup) {
      const newGroups = {};
      for (let group in Vvveb.ComponentsGroup) {
        let tGroup = translateText(group);
        newGroups[tGroup] = Vvveb.ComponentsGroup[group];
        newGroups[tGroup].forEach(compName => {
          let comp = Vvveb.Components.get(compName);
          if (comp && comp.name) {
            comp.name = translateText(comp.name);
          }
        });
      }
      Vvveb.ComponentsGroup = newGroups;
    }

    if (Vvveb.BlocksGroup) {
      const newBlockGroups = {};
      for (let group in Vvveb.BlocksGroup) {
        let tGroup = translateText(group);
        newBlockGroups[tGroup] = Vvveb.BlocksGroup[group];
      }
      Vvveb.BlocksGroup = newBlockGroups;
    }

    // 2. 翻譯所有元件的屬性面板 (Style, Advanced, etc)
    if (Vvveb.Components && Vvveb.Components._components) {
      Object.keys(Vvveb.Components._components).forEach(key => {
        let comp = Vvveb.Components._components[key];
        if (comp.properties) {
          comp.properties.forEach(prop => {
            if (prop.name) prop.name = translateText(prop.name);
            if (prop.data) {
              if (prop.data.header) prop.data.header = translateText(prop.data.header);
              if (prop.data.text) prop.data.text = translateText(prop.data.text);
              if (prop.data.options && Array.isArray(prop.data.options)) {
                prop.data.options.forEach(opt => {
                  if (opt.text) opt.text = translateText(opt.text);
                  if (opt.title) opt.title = translateText(opt.title);
                  if (opt.optgroup) opt.optgroup = translateText(opt.optgroup);
                });
              }
            }
          });
        }
      });
    }

    // 3. 直接修改當前已渲染的 DOM 文字
    document.querySelectorAll(".components-list .header span, .blocks-list .header span, .sections-list .header span").forEach(el => {
      const txt = el.textContent.trim();
      if (translateMap[txt]) {
        el.textContent = translateMap[txt];
      }
    });

    document.querySelectorAll(".components-list li .name, .blocks-list li .name, .sections-list li .name").forEach(el => {
      const txt = el.textContent.trim();
      if (translateMap[txt]) {
        // 如果有子元素，只替換文本節點
        if (el.childNodes.length > 0) {
           for (let i = 0; i < el.childNodes.length; i++) {
             if (el.childNodes[i].nodeType === 3 && el.childNodes[i].textContent.trim() === txt) {
                el.childNodes[i].textContent = translateMap[txt];
                break;
             }
           }
        } else {
           el.textContent = translateMap[txt];
        }
      }
    });

    console.log("[my-editor] VvvebJS components and blocks localized.");
  }

  // ── 啟用 Save 按鈕（vvvebjs 預設 disabled）──────────────────────
  function enableSaveBtn() {
    const btn = document.querySelector(".save-btn");
    if (btn) {
      btn.removeAttribute("disabled");
    } else {
      setTimeout(enableSaveBtn, 300);
    }
  }

  // ── Ctrl+S 快捷鍵 ────────────────────────────────────────────────
  document.addEventListener("keydown", function (e) {
    if ((e.ctrlKey || e.metaKey) && e.key === "s") {
      e.preventDefault();
      if (typeof Vvveb !== "undefined" && Vvveb.Builder && Vvveb.Builder.saveAjax) {
        // 觸發原生儲存按鈕的 click
        const btn = document.querySelector(".save-btn");
        if (btn) {
          btn.click();
        } else {
          Vvveb.Builder.saveAjax({});
        }
      }
    }
  });

  // ── 初始化 ────────────────────────────────────────────────────────
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", () => {
      patchSaveAjax();
      patchFileManager();
      patchNewSection();
      patchPageTree();
      patchI18n();
      enableSaveBtn();
      initCKEditorOverride();
    });
  } else {
    patchSaveAjax();
    patchFileManager();
    patchNewSection();
    patchPageTree();
    patchI18n();
    enableSaveBtn();
    initCKEditorOverride();
  }

  // ── 動態載入並覆寫 CKEditor ───────────────────────────────────────
  function initCKEditorOverride() {
    const script = document.createElement("script");
    script.src = "https://cdn.ckeditor.com/4.22.1/full-all/ckeditor.js";
    script.onload = () => {
      // 隱藏版本過期警告
      if (CKEDITOR.config) {
        CKEDITOR.config.versionCheck = false;
      }

      const ckeditorOptions = {
        extraPlugins: "sharedspace",
        removePlugins: "exportpdf", // 解決 exportpdf-no-token-url 錯誤
        sharedSpaces: {
          top: "#wysiwyg-editor",
        }
      };

      // 覆寫 Vvveb 原生的 WysiwygEditor，改用 Vanilla JS
      Vvveb.WysiwygEditor = {
        isActive: false,
        oldValue: '',
        doc: false,
        editor: false,
        toolbar: false,
        
        init: function(doc) {
          this.doc = doc;
          this.toolbar = document.getElementById('wysiwyg-editor');
          if (this.toolbar) {
            this.toolbar.classList.remove("default-editor");
            this.toolbar.classList.add("ckeditor");
            this.toolbar.innerHTML = '';
          }
        },
        
        edit: function(element) {
          this.element = element;
          this.isActive = true;
          this.oldValue = element.innerHTML;
          Vvveb.Builder.selectPadding = 10;
          
          element.setAttribute('contenteditable', true);
          element.setAttribute('spellcheckker', false);
          
          CKEDITOR.disableAutoInline = true;
          ckeditorOptions.sharedSpaces.top = this.toolbar;
          
          if (this.editor) {
            try { this.editor.destroy(); } catch(e) {}
          }
          this.editor = CKEDITOR.inline(element, ckeditorOptions);
          
          if (this.toolbar) {
            this.toolbar.style.display = "block";
          }
        },

        destroy: function(element) {
          this.isActive = false;
          
          if (this.editor) {
            try {
              this.editor.destroy();
            } catch (e) {
              console.warn("[my-editor] CKEditor destroy error", e);
            }
            this.editor = false;
          }
          
          if (element) {
            element.removeAttribute('contenteditable');
            element.removeAttribute('spellcheckker');
            
            // 清除 CKEditor 殘留屬性，避免破壞 DOM 導致 VvvebJs 報錯
            element.classList.remove('cke_editable', 'cke_editable_inline', 'cke_focus');
            
            // 嘗試修復 Vvveb.Builder.selectedEl 為 null 的問題
            if (typeof Vvveb.Builder !== "undefined" && !Vvveb.Builder.selectedEl) {
               Vvveb.Builder.selectedEl = element;
            }
          }

          if (this.toolbar) {
            this.toolbar.style.display = "none";
          }
          
          const node = this.element || element;
          if (node && Vvveb.Undo) {
            Vvveb.Undo.addMutation({
              type: 'characterData', 
              target: node, 
              oldValue: this.oldValue, 
              newValue: node.innerHTML
            });
          }
        }
      };

      // 嘗試立即初始化，以綁定 `#wysiwyg-editor` 元素
      if (typeof Vvveb !== "undefined" && Vvveb.Builder && Vvveb.Builder.iframe) {
         Vvveb.WysiwygEditor.init(Vvveb.Builder.iframe.contentDocument);
      }
      
      console.log("[my-editor] CKEditor 4 external override injected successfully.");
    };
    
    document.head.appendChild(script);
  }
})();
