if (typeof window.VUNELIX_API_URL !== 'string' || !window.VUNELIX_API_URL) {
    window.VUNELIX_API_URL = 'https://vunelix.com/';
}

import { sendPostRequest } from "../services/http.js";

import { addThousandSeparator, scrollToCenter } from "../utils/helper.js";

import { WebSocketManager } from "../services/webSocket.js";

import { initCustomSelects } from "../components/custom-select.js";

import { initializeTooltips } from "../components/custom-tooltip.js";

import { initLazyLoad } from "../components/lazyload.js";

class VunelivBase extends HTMLElement {
    static cssVersion="3.8.6";
    static commonCssFile="main";
    static rtlLangs=[ "ar", "he", "fa", "ur" ];
    static widgetCss=[];
    static langFile="screener";
    static langStoreKey="";
    constructor() {
        super();
        this.root = this.attachShadow({
            mode: "open"
        });
        this.config = {};
        this._initialized = false;
        this._contentEl = document.createElement("div");
        this._contentEl.className = "vnx-widget-root";
        this._contentEl.style.cssText = "position:relative";
        this.root.appendChild(this._contentEl);
    }
    #loadCss(isRtl) {
        const cssUrl = this.#getCssUrl();
        const v = VunelivBase.cssVersion;
        const files = [ VunelivBase.commonCssFile, ...this.constructor.widgetCss ];
        if (isRtl) files.push("rtl");
        for (const file of files) {
            const link = document.createElement("link");
            link.rel = "stylesheet";
            link.href = `${cssUrl}${file}.css?v=${v}`;
            this.root.appendChild(link);
        }
    }
    connectedCallback() {
        if (this._initialized) return;
        this._initialized = true;
        const lang = this.dataset.lang || "en";
        const isRtl = VunelivBase.rtlLangs.includes(lang);
        this._contentEl.setAttribute("dir", isRtl ? "rtl" : "ltr");
        this._contentEl.setAttribute("lang", lang);
        this.#applyTheme();
        this.#loadCss(VunelivBase.rtlLangs.includes(lang));
        if (!this.dataset.loadingEl) this.#showLoading();
        if (this.constructor.branding_bar && this.dataset.removeBranding !== "true") {
            this.#showInstantBranding();
        }
        this.#observeVisibility();
    }
    #applyTheme() {
        const raw = this.dataset.theme || "auto";
        if (raw !== "auto") {
            this.#setTheme(raw);
            return;
        }
        this.#setTheme(this.#detectSiteTheme());
        const html = document.documentElement;
        this._themeObserver = new MutationObserver(() => this.#setTheme(this.#detectSiteTheme()));
        this._themeObserver.observe(html, {
            attributes: true
        });
        if (document.body) this._themeObserver.observe(document.body, {
            attributes: true
        });
        this._themeMedia = window.matchMedia("(prefers-color-scheme: dark)");
        this._themeMedia.addEventListener("change", () => this.#setTheme(this.#detectSiteTheme()));
    }
    #detectSiteTheme() {
        for (const el of [ document.documentElement, document.body ]) {
            if (!el) continue;
            for (const attr of el.attributes) {
                if (attr.name === "style" || attr.name === "class") continue;
                const v = attr.value.toLowerCase();
                if (v === "dark") return "dark";
                if (v === "light") return "light";
            }
            if (el.classList.contains("dark")) return "dark";
        }
        const cs = getComputedStyle(document.documentElement).colorScheme;
        if (cs === "dark") return "dark";
        if (cs === "light") return "light";
        if (window.matchMedia("(prefers-color-scheme: dark)").matches) return "dark";
        return "light";
    }
    #setTheme(theme) {
        if (this._contentEl.getAttribute("data-theme") === theme) return;
        this.classList.add("theme-transitioning");
        this._contentEl.setAttribute("data-theme", theme);
        this.setAttribute("data-theme", theme);
        void this._contentEl.offsetHeight;
        requestAnimationFrame(() => this.classList.remove("theme-transitioning"));
    }
    #observeVisibility() {
        const observer = new IntersectionObserver(entries => {
            if (entries[0].isIntersecting) {
                observer.disconnect();
                this.#fetchWidget();
            }
        }, {
            rootMargin: "200px"
        });
        observer.observe(this);
    }
    #showLoading() {
        if (this.constructor.showLoading === false) return;
        const skeleton = this.getSkeletonHtml?.() || this.constructor.skeletonHtml;
        if (skeleton) {
            this._contentEl.innerHTML = skeleton;
            return;
        }
        this._contentEl.innerHTML = `\n            <style>\n                .widget-loading { display:flex; align-items:center; justify-content:center; min-height:200px; }\n                .loading-spinner { width:32px; height:32px; border:3px solid #e2e8f0; border-top-color:#3b82f6; border-radius:50%; animation:vnx-spin .6s linear infinite; }\n                @keyframes vnx-spin { to { transform:rotate(360deg) } }\n            </style>\n            <div class="widget-loading"><div class="loading-spinner"></div></div>\n        `;
    }
    #showError(message) {
        const linked = message.replace(/(https?:\/\/[^\s<]+)/g, '<a href="$1" target="_blank" rel="noopener" style="color:#3B82F6;text-decoration:underline">$1</a>');
        this._contentEl.innerHTML = `\n            <style>.widget-error{display:flex;align-items:center;justify-content:center;gap:8px;min-height:80px;color:#64748B;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-size:13px;text-align:center;padding:20px;line-height:1.5}.widget-error svg{flex-shrink:0;color:#94A3B8}</style>\n            <div class="widget-error">\n                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n                    <circle cx="12" cy="12" r="10" stroke-width="2"/>\n                    <line x1="12" y1="16" x2="12" y2="12" stroke-width="2" stroke-linecap="round"/>\n                    <circle cx="12" cy="8" r="1" fill="currentColor" stroke="none"/>\n                </svg>\n                <span>${linked}</span>\n            </div>\n        `;
    }
    async #fetchWidget() {
        try {
            const baseUrl = this.#getBaseUrl();
            const userConfig = this.#getDataConfig();
            if (this.clampConfig) this.clampConfig(userConfig);
            const response = await this.#fetchRender(baseUrl, userConfig);
            if (response?.status) {
                this.#injectResponse(response);
            } else {
                this.#showError(response?.message || "Failed to load widget");
            }
        } catch (error) {
            console.error("Vunelix Widget Error:", error);
            this.#showError("Failed to load widget");
        }
    }
    async #fetchRender(baseUrl, userConfig) {
        const body = new URLSearchParams;
        body.append("slug", this.constructor.slug || "");
        body.append("config", JSON.stringify(userConfig));
        try {
            body.append("page_url", window.location.href);
        } catch (e) {}
        const response = await fetch(`${baseUrl}embed/render`, {
            method: "POST",
            mode: "cors",
            body: body
        });
        if (!response.ok && response.status !== 403) {
            throw new Error(`HTTP ${response.status}`);
        }
        return await response.json();
    }
    #getBaseUrl() {
        if (typeof window.VUNELIX_API_URL === "string" && window.VUNELIX_API_URL) return window.VUNELIX_API_URL;
        const markers = [ "assets/bundles/js/widgets/", "assets/js/widgets/" ];
        const scripts = document.querySelectorAll('script[src*="vunelix-"]');
        for (const script of scripts) {
            const src = script.getAttribute("src");
            if (src) {
                for (const marker of markers) {
                    const idx = src.indexOf(marker);
                    if (idx !== -1) return src.substring(0, idx);
                }
            }
        }
        return window.location.origin + "/";
    }
    #getCssUrl() {
        if (typeof window.VUNELIX_CSS_URL === "string" && window.VUNELIX_CSS_URL) return window.VUNELIX_CSS_URL;
        const baseUrl = this.#getBaseUrl();
        const scripts = document.querySelectorAll('script[src*="vunelix-"]');
        for (const script of scripts) {
            if (script.getAttribute("src")?.includes("assets/bundles/")) {
                return baseUrl + "assets/bundles/css/";
            }
        }
        return baseUrl + "assets/css/";
    }
    #getDataConfig() {
        const config = {};
        for (const attr of this.attributes) {
            if (attr.name.startsWith("data-")) {
                const key = attr.name.substring(5).replace(/-/g, "_");
                let value = attr.value;
                if (value === "true") value = true; else if (value === "false") value = false; else if (!isNaN(value) && value !== "") value = Number(value);
                config[key] = value;
            }
        }
        return config;
    }
    #injectResponse(data) {
        const {html: html, icons: icons, config: config, branding: branding} = data;
        this.config = config || {};
        if (branding && this.constructor.branding_bar) {
            if (!this._brandingEl) this.#showInstantBranding();
            this.#guardBranding();
        } else if (this._brandingEl) {
            this._brandingEl.remove();
            this._brandingEl = null;
        }
        this._contentEl.style.cssText = "position:relative";
        const pairs = [ [ "positiveColor", [ "--color-green", "--color-success" ], "--green-rgb" ], [ "negativeColor", [ "--color-red", "--color-danger" ], "--red-rgb" ], [ "bgColor", [ "--bg-primary" ], null ], [ "bgSecondaryColor", [ "--bg-secondary", "--cross-highlight" ], null ], [ "textColor", [ "--text-primary" ], null ], [ "textSecondaryColor", [ "--text-secondary" ], null ], [ "borderColor", [ "--border-light" ], null ] ];
        let lightCss = "", darkCss = "";
        for (const [attr, cssVars, rgbVar] of pairs) {
            const val = this.dataset[attr];
            if (!val || !val.includes(",")) continue;
            const [light, dark] = val.split(",");
            if (light) {
                for (const v of cssVars) lightCss += `${v}:${light};`;
                if (rgbVar) {
                    const rgb = this.#hexToRgb(light);
                    if (rgb) lightCss += `${rgbVar}:${rgb};`;
                }
            }
            if (dark) {
                for (const v of cssVars) darkCss += `${v}:${dark};`;
                if (rgbVar) {
                    const rgb = this.#hexToRgb(dark);
                    if (rgb) darkCss += `${rgbVar}:${rgb};`;
                }
            }
        }
        let overrideCss = "";
        if (lightCss) overrideCss += `.vnx-widget-root{${lightCss}}`;
        if (darkCss) overrideCss += `.vnx-widget-root[data-theme="dark"]{${darkCss}}`;
        if (config?.transparentBg) overrideCss += ".heatmap-container,.fx-table tr td,.fx-table tr th,.cross-rates-table-container,.converter-card,.infinite-marquee-wrapper{background-color:transparent !important}";
        let content = "";
        if (overrideCss || config?.customCss) content += `<style>${overrideCss}${config?.customCss || ""}</style>`;
        if (icons) content += icons;
        content += html || "";
        this._contentEl.innerHTML = content;
        this.#waitForCss().then(async () => {
            await this.#loadWidgetLang();
            window.BASE_PATH = this.config.BASE_PATH || this.config.BASE_URL || this.#getBaseUrl();
            window.BASE_URL = this.config.BASE_URL || window.BASE_PATH;
            if (this.config.ICON_PATH) window.ICON_PATH = this.config.ICON_PATH;
            if (this.config.ICON_TYPE) window.ICON_TYPE = this.config.ICON_TYPE;
            if (this.config.API_ENDPOINT) window.API_ENDPOINT = this.config.API_ENDPOINT;
            window.sendPostRequest = (url, data, opts) => this.widgetSendPostRequest(url, data, opts);
            initCustomSelects(null, this.root);
            initializeTooltips(this.root);
            initLazyLoad(this.root);
            if (this.constructor.useSocket !== false && this.config.SOCKET_API_KEY) {
                const ws = new WebSocketManager({
                    rootNode: this.root,
                    apiKey: this.config.SOCKET_API_KEY || "none",
                    ...this.getSocketConfig?.() || {}
                });
                ws.connect();
                window.webSocketService = ws;
                this._webSocket = ws;
            }
            this.onReady(this.root, this.config);
            if (this._webSocket) {
                const mode = this.config.animationMode ?? "digits";
                const duration = this.config.animationDuration ?? 1500;
                switch (mode) {
                  case "full":
                    this._webSocket.config.animateFullValue = true;
                    this._webSocket.config.animateBgFlash = false;
                    this._webSocket.config.animationDuration = duration;
                    break;

                  case "flash":
                    this._webSocket.config.animateFullValue = true;
                    this._webSocket.config.animateBgFlash = true;
                    this._webSocket.config.animationDuration = duration;
                    break;

                  case "none":
                    this._webSocket.config.animationDuration = 0;
                    this._webSocket.config.animateBgFlash = false;
                    break;

                  default:
                    this._webSocket.config.animateFullValue = false;
                    this._webSocket.config.animateBgFlash = false;
                    this._webSocket.config.animationDuration = duration;
                    break;
                }
            }
            const sel = this.dataset.loadingEl;
            if (sel) {
                try {
                    document.querySelectorAll(sel).forEach(el => el.remove());
                } catch (e) {}
            }
        });
    }
    #getBrandingUrl(slug) {
        if (this.constructor.branding_url) return this.constructor.branding_url;
        const base = this.#getBaseUrl();
        if (this.constructor.branding_path) return base + this.constructor.branding_path;
        return base + "widgets/" + slug;
    }
    #showInstantBranding() {
        if (this._brandingEl) return;
        const slug = this.constructor.slug || "";
        const name = slug.replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase());
        const url = this.#getBrandingUrl(slug);
        const wrap = document.createElement("div");
        wrap.className = "vnx-credit";
        wrap.style.cssText = "display:block;text-align:right;font:14px/2 -apple-system,BlinkMacSystemFont,sans-serif !important;color:#94a3b8 !important;padding:2px 4px;margin-top:15px";
        const link = document.createElement("a");
        link.href = url;
        link.target = "_blank";
        link.rel = "noopener noreferrer";
        link.textContent = name;
        link.style.cssText = "color:#3b82f6 !important;text-decoration:none";
        wrap.appendChild(link);
        wrap.append(" by Vunelix");
        this._brandingEl = wrap;
        this.after(wrap);
    }
    #guardBranding() {
        const slug = this.constructor.slug || "";
        const origText = slug.replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase());
        const url = this.#getBrandingUrl(slug);
        const origHost = new URL(url).hostname;
        const kill = () => {
            clearInterval(this._brandingTimer);
            this._brandingObserver?.disconnect();
            this._brandingEl?.remove();
            this._contentEl.innerHTML = `\n                <div style="display:flex;align-items:center;justify-content:center;min-height:100px;font-family:-apple-system,BlinkMacSystemFont,sans-serif;text-align:center;padding:20px;color:#94A3B8;font-size:13px">\n                    Widget disabled — branding attribution is required.\n                </div>`;
        };
        const check = () => {
            const el = this._brandingEl;
            if (!el || !el.isConnected) {
                kill();
                return;
            }
            const link = el.querySelector("a");
            if (!link || !link.href.includes(origHost) || !link.textContent.includes(origText)) {
                kill();
                return;
            }
            const s = getComputedStyle(el);
            const sLink = getComputedStyle(link);
            if (s.display === "none" || s.visibility === "hidden" || parseFloat(s.opacity) < .5) {
                kill();
                return;
            }
            if (el.offsetHeight < 5 || el.offsetWidth < 5) {
                kill();
                return;
            }
            if (parseFloat(s.fontSize) < 5 || parseFloat(sLink.fontSize) < 5) {
                kill();
                return;
            }
            if (s.position === "fixed" || s.position === "absolute") {
                const rect = el.getBoundingClientRect();
                if (rect.right < 0 || rect.bottom < 0 || rect.left > window.innerWidth || rect.top > window.innerHeight) {
                    kill();
                    return;
                }
            }
            if (parseFloat(s.textIndent) < -100) {
                kill();
                return;
            }
            if (s.transform && s.transform !== "none") {
                const m = s.transform.match(/matrix\(([^,]+)/);
                if (m && Math.abs(parseFloat(m[1])) < .1) {
                    kill();
                    return;
                }
            }
            if (s.clipPath && s.clipPath !== "none" && s.clipPath.includes("inset")) {
                kill();
                return;
            }
            const c = sLink.color;
            if (c === "transparent" || c === "rgba(0, 0, 0, 0)") {
                kill();
                return;
            }
        };
        check();
        [ 2e3, 5e3, 1e4, 2e4, 4e4, 6e4 ].forEach(d => setTimeout(check, d));
        this._brandingObserver = new MutationObserver(() => {
            if (!this._brandingEl?.isConnected) kill();
        });
        this._brandingObserver.observe(this._brandingEl.parentNode, {
            childList: true
        });
    }
    #waitForCss() {
        const links = this.root.querySelectorAll('link[rel="stylesheet"]');
        if (links.length === 0) return Promise.resolve();
        const promises = Array.from(links).map(link => {
            if (link.sheet) return Promise.resolve();
            return new Promise(resolve => {
                link.addEventListener("load", resolve, {
                    once: true
                });
                link.addEventListener("error", resolve, {
                    once: true
                });
            });
        });
        return Promise.all(promises);
    }
    _langData=null;
    async #loadWidgetLang() {
        const lang = this.dataset.lang || "en";
        const langFile = this.constructor.langFile || "screener";
        const storeKey = this.constructor.langStoreKey || "";
        try {
            const jsUrl = this.config.JS_URL;
            const res = await fetch(`${jsUrl}lang/${lang}/${langFile}.json`);
            if (res.ok) {
                this._langData = await res.json();
                window.LANG = window.LANG || {};
                if (storeKey) {
                    window.LANG[storeKey] = this._langData;
                } else {
                    Object.assign(window.LANG, this._langData);
                }
            }
        } catch (_) {}
    }
    widgetGetLang(path, fallback = "") {
        if (!this._langData || !path) return fallback;
        const keys = path.split(".");
        let value = this._langData;
        for (const key of keys) {
            value = value?.[key.toLowerCase()];
            if (value === undefined) return fallback;
        }
        return value || fallback;
    }
    onReady(root, config) {}
    widgetSendPostRequest(url, data = {}, options = {}) {
        return sendPostRequest(url, data, {
            ...options,
            auth: this.config?.AUTH || null
        });
    }
    #hexToRgb(hex) {
        hex = hex.replace("#", "");
        if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
        if (hex.length !== 6) return null;
        const n = parseInt(hex, 16);
        return `${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}`;
    }
}

export { VunelivBase, sendPostRequest, addThousandSeparator, initCustomSelects, scrollToCenter };