class DecypharrUtils{constructor(){this.urlBase=window.urlBase||"",this.toastContainer=null,this.init()}init(){this.setupToastSystem(),this.setupThemeToggle(),this.setupPasswordToggles(),this.setupVersionInfo(),this.setupGlobalEventListeners(),this.createToastContainer()}createToastContainer(){let e=document.querySelector(".toast-container");e||(e=document.createElement("div"),e.className="toast-container fixed bottom-4 right-4 z-50 space-y-2",document.body.appendChild(e)),this.toastContainer=e}setupToastSystem(){this.addToastStyles(),window.addEventListener("error",e=>{console.error("Global error:",e.error),this.createToast(`Unexpected error: ${e.error?.message||"Unknown error"}`,"error")}),window.addEventListener("unhandledrejection",e=>{console.error("Unhandled promise rejection:",e.reason),this.createToast(`Promise rejected: ${e.reason?.message||"Unknown error"}`,"error")})}addToastStyles(){if(document.getElementById("toast-styles"))return;const e=document.createElement("style");e.id="toast-styles",e.textContent="\n @keyframes toastSlideIn {\n from {\n opacity: 0;\n transform: translateX(100%);\n }\n to {\n opacity: 1;\n transform: translateX(0);\n }\n }\n\n @keyframes toastSlideOut {\n from {\n opacity: 1;\n transform: translateX(0);\n }\n to {\n opacity: 0;\n transform: translateX(100%);\n }\n }\n\n .toast-container .alert {\n animation: toastSlideIn 0.3s ease-out;\n max-width: 400px;\n word-wrap: break-word;\n }\n\n .toast-container .alert.toast-closing {\n animation: toastSlideOut 0.3s ease-in forwards;\n }\n\n @media (max-width: 640px) {\n .toast-container {\n left: 1rem;\n right: 1rem;\n bottom: 1rem;\n }\n \n .toast-container .alert {\n max-width: none;\n }\n }\n ",document.head.appendChild(e)}joinURL(e,t){return e.endsWith("/")||(e+="/"),t.startsWith("/")&&(t=t.substring(1)),e+t}async fetcher(e,t={}){const n=this.joinURL(this.urlBase,e),o={headers:{},...t};t.body instanceof FormData||(o.headers["Content-Type"]="application/json"),o.headers={...o.headers,...t.headers};try{const e=await fetch(n,o);return t.loadingButton&&this.setButtonLoading(t.loadingButton,!1),e}catch(e){throw t.loadingButton&&this.setButtonLoading(t.loadingButton,!1),e}}createToast(e,t="success",n=null){t=["success","warning","error","info"].includes(t)?t:"success",n=n||{success:5e3,warning:1e4,error:15e3,info:7e3}[t],this.toastContainer||this.createToastContainer();const o=`toast-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,s=`\n
\n
\n
\n ${{success:' ',error:' ',warning:' ',info:' '}[t]}\n \n
\n ${e.replace(/\n/g," ")} \n
\n
\n \n \n \n \n
\n
\n `;this.toastContainer.insertAdjacentHTML("beforeend",s);const a=setTimeout(()=>this.closeToast(o),n),r=document.getElementById(o);return r&&(r.dataset.timeoutId=a),o}closeToast(e){const t=document.getElementById(e);t&&(t.dataset.timeoutId&&clearTimeout(parseInt(t.dataset.timeoutId)),t.classList.add("toast-closing"),setTimeout(()=>{t.parentNode&&t.remove()},300))}closeAllToasts(){const e=this.toastContainer?.querySelectorAll(".alert");e&&e.forEach(e=>{e.id&&this.closeToast(e.id)})}setButtonLoading(e,t=!0,n=null){"string"==typeof e&&(e=document.getElementById(e)||document.querySelector(e)),e&&(t?(e.disabled=!0,e.dataset.originalText||(e.dataset.originalText=n||e.innerHTML),e.innerHTML=' Processing...',e.classList.add("loading-state")):(e.disabled=!1,e.innerHTML=e.dataset.originalText||"Submit",e.classList.remove("loading-state"),delete e.dataset.originalText))}setupPasswordToggles(){document.addEventListener("click",e=>{const t=e.target.closest(".password-toggle-btn");if(t){e.preventDefault(),e.stopPropagation();const n=t.closest(".password-toggle-container");if(n){const e=n.querySelector("input, textarea"),o=t.querySelector("i");e&&o&&this.togglePasswordField(e,o)}}})}togglePasswordField(e,t){t&&("textarea"===e.tagName.toLowerCase()?this.togglePasswordTextarea(e,t):this.togglePasswordInput(e,t))}togglePasswordInput(e,t){"password"===e.type?(e.type="text",t.className="bi bi-eye-slash"):(e.type="password",t.className="bi bi-eye")}togglePasswordTextarea(e,t){"disc"===e.style.webkitTextSecurity||""===e.style.webkitTextSecurity||"true"!==e.getAttribute("data-password-visible")?(e.style.webkitTextSecurity="none",e.style.textSecurity="none",e.setAttribute("data-password-visible","true"),t.className="bi bi-eye-slash"):(e.style.webkitTextSecurity="disc",e.style.textSecurity="disc",e.setAttribute("data-password-visible","false"),t.className="bi bi-eye")}togglePassword(e){const t=document.getElementById(e),n=t?.closest(".password-toggle-container")?.querySelector(".password-toggle-btn");let o=n.querySelector("i");t&&o&&this.togglePasswordField(t,o)}setupThemeToggle(){const e=document.getElementById("themeToggle"),t=document.documentElement;if(!e)return;const n=n=>{t.setAttribute("data-theme",n),localStorage.setItem("theme",n),e.checked="dark"===n,document.body.style.transition="background-color 0.3s ease, color 0.3s ease",setTimeout(()=>{document.body.style.transition=""},300),window.dispatchEvent(new CustomEvent("themechange",{detail:{theme:n}}))},o=localStorage.getItem("theme");o?n(o):window.matchMedia?.("(prefers-color-scheme: dark)").matches?n("dark"):n("light"),e.addEventListener("change",()=>{const e=t.getAttribute("data-theme");n("dark"===e?"light":"dark")}),window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",e=>{localStorage.getItem("theme")||n(e.matches?"dark":"light")})}async setupVersionInfo(){try{const e=await this.fetcher("/version");if(!e.ok)throw new Error("Failed to fetch version");const t=await e.json(),n=document.getElementById("version-badge");n&&(n.innerHTML=`\n \n ${t.channel}-${t.version}\n \n `,n.classList.remove("badge-warning","badge-error","badge-ghost"),"beta"===t.channel?n.classList.add("badge-warning"):"nightly"===t.channel&&n.classList.add("badge-error"))}catch(e){console.error("Error fetching version:",e);const t=document.getElementById("version-badge");t&&(t.textContent="Unknown",t.classList.add("badge-ghost"))}}setupMobileNavigation(){const e=document.querySelector('.navbar-start .dropdown [role="button"]'),t=document.querySelector(".navbar-start .dropdown .dropdown-content"),n=document.querySelector(".navbar-start .dropdown");if(!e||!t||!n)return;let o=!1;const s=()=>{o&&(n.classList.remove("dropdown-open"),e.setAttribute("aria-expanded","false"),o=!1)},a=t=>{t.preventDefault(),t.stopPropagation(),o?s():o||(n.classList.add("dropdown-open"),e.setAttribute("aria-expanded","true"),o=!0)};e.addEventListener("click",a),e.addEventListener("touchend",e=>{e.preventDefault(),a(e)}),document.addEventListener("click",e=>{o&&!n.contains(e.target)&&s()}),document.addEventListener("touchend",e=>{o&&!n.contains(e.target)&&s()}),t.addEventListener("click",e=>{"A"===e.target.tagName&&s()}),e.addEventListener("keydown",e=>{"Enter"===e.key||" "===e.key?(e.preventDefault(),a(e)):"Escape"===e.key&&s()}),e.setAttribute("aria-expanded","false"),e.setAttribute("aria-haspopup","true")}setupGlobalEventListeners(){this.setupMobileNavigation(),document.addEventListener("click",e=>{const t=e.target.closest('a[href^="#"]');if(t&&"#"!==t.getAttribute("href")){e.preventDefault();const n=document.querySelector(t.getAttribute("href"));n&&n.scrollIntoView({behavior:"smooth",block:"start"})}}),document.addEventListener("invalid",e=>{e.target.classList.add("input-error"),setTimeout(()=>e.target.classList.remove("input-error"),3e3)},!0),document.addEventListener("keydown",e=>{"Escape"===e.key&&(document.querySelectorAll(".modal[open]").forEach(e=>e.close()),document.querySelectorAll(".dropdown-open").forEach(e=>{e.classList.remove("dropdown-open")}),document.querySelectorAll(".context-menu:not(.hidden)").forEach(e=>{e.classList.add("hidden")})),(e.ctrlKey||e.metaKey)&&"/"===e.key&&(e.preventDefault(),this.showKeyboardShortcuts())}),document.addEventListener("visibilitychange",()=>{document.hidden?window.dispatchEvent(new CustomEvent("pageHidden")):window.dispatchEvent(new CustomEvent("pageVisible"))}),window.addEventListener("online",()=>{this.createToast("Connection restored","success")}),window.addEventListener("offline",()=>{this.createToast("Connection lost - working offline","warning")})}showKeyboardShortcuts(){const e=document.createElement("dialog");e.className="modal",e.innerHTML=`\n \n
\n
Keyboard Shortcuts \n
\n ${[{key:"Esc",description:"Close modals and dropdowns"},{key:"Ctrl + /",description:"Show this help"},{key:"Ctrl + R",description:"Refresh page"}].map(e=>`\n
\n ${e.key} \n ${e.description} \n
\n `).join("")}\n
\n
\n `,document.body.appendChild(e),e.showModal(),e.addEventListener("close",()=>{document.body.removeChild(e)})}formatBytes(e){if(!e||0===e)return"0 B";const t=Math.floor(Math.log(e)/Math.log(1024));return`${parseFloat((e/Math.pow(1024,t)).toFixed(2))} ${["B","KB","MB","GB","TB","PB"][t]}`}formatSpeed(e){return`${this.formatBytes(e)}/s`}formatDuration(e){if(!e||0===e)return"0s";const t=[{label:"d",seconds:86400},{label:"h",seconds:3600},{label:"m",seconds:60},{label:"s",seconds:1}],n=[];let o=e;for(const e of t){const t=Math.floor(o/e.seconds);t>0&&(n.push(`${t}${e.label}`),o%=e.seconds)}return n.slice(0,2).join(" ")||"0s"}debounce(e,t,n=!1){let o;return function(...s){const a=n&&!o;clearTimeout(o),o=setTimeout(()=>{o=null,n||e(...s)},t),a&&e(...s)}}throttle(e,t){let n;return function(...o){n||(e.apply(this,o),n=!0,setTimeout(()=>n=!1,t))}}async copyToClipboard(e){try{return await navigator.clipboard.writeText(e),this.createToast("Copied to clipboard","success"),!0}catch(e){return console.error("Failed to copy to clipboard:",e),this.createToast("Failed to copy to clipboard","error"),!1}}isValidUrl(e){try{return new URL(e),!0}catch(e){return!1}}escapeHtml(e){const t={"&":"&","<":"<",">":">",'"':""","'":"'"};return e?e.replace(/[&<>"']/g,e=>t[e]):""}getCurrentTheme(){return document.documentElement.getAttribute("data-theme")||"light"}isOnline(){return navigator.onLine}}window.decypharrUtils=new DecypharrUtils,window.fetcher=(e,t={})=>window.decypharrUtils.fetcher(e,t),window.createToast=(e,t,n)=>window.decypharrUtils.createToast(e,t,n),"undefined"!=typeof module&&module.exports&&(module.exports=DecypharrUtils);