// /AIWK_COMMON/modules/core/selector_tool.js
// AIWK EXT4 v123 - common selector tool module
(function () {
    "use strict";
    const VERSION = "v123-binding-state-label-hotfix";
    const MODULE_ID = "core.selector.tool";
    if (window.__AIWK_CORE_SELECTOR_TOOL_V118__) return;
    window.__AIWK_CORE_SELECTOR_TOOL_V118__ = true;

    function safeString(v) { return v === undefined || v === null ? "" : String(v); }
    function nowText() { try { return new Date().toLocaleTimeString(); } catch (err) { return ""; } }
    function frameInfo() { return { module_id: MODULE_ID, version: VERSION, is_top: window.top === window, href: location.href, hostname: location.hostname || "", title: document.title || "" }; }
    function sendEvent(action, event) {
        try { chrome.runtime.sendMessage({ type: "AIWK_IFRAME_AGENT_EVENT", action: action || "selector_tool", frame: frameInfo(), event: Object.assign({ module_id: MODULE_ID }, event || {}) }).catch(function () {}); } catch (err) {}
    }
    function cssPath(el) {
        if (!el || el.nodeType !== 1) return "";
        if (el.id) return "#" + String(el.id).replace(/([ #;?%&,.+*~':"!^$[\]()=>|\/@])/g, "\\$1");
        const parts = [];
        let cur = el;
        for (let depth = 0; cur && cur.nodeType === 1 && depth < 8; depth += 1) {
            let name = cur.nodeName.toLowerCase();
            if (cur.classList && cur.classList.length) name += "." + Array.from(cur.classList).slice(0, 2).map(function (c) { return String(c).replace(/([ #;?%&,.+*~':"!^$[\]()=>|\/@])/g, "\\$1"); }).join(".");
            const parent = cur.parentElement;
            if (parent) {
                const same = Array.from(parent.children).filter(function (x) { return x.nodeName === cur.nodeName; });
                if (same.length > 1) name += ":nth-of-type(" + (same.indexOf(cur) + 1) + ")";
            }
            parts.unshift(name);
            cur = parent;
        }
        return parts.join(" > ");
    }
    function describe(el) {
        if (!el) return null;
        const r = el.getBoundingClientRect ? el.getBoundingClientRect() : null;
        return {
            tag: el.tagName || "", id: el.id || "", className: safeString(el.className || ""),
            text: safeString(el.innerText || el.textContent || "").slice(0, 500),
            value: "value" in el ? safeString(el.value).slice(0, 500) : "",
            contenteditable: el.getAttribute ? safeString(el.getAttribute("contenteditable") || "") : "",
            selector_path: cssPath(el),
            rect: r ? { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) } : null
        };
    }
    function queryDeep(root, selector, opt) {
        opt = opt || {};
        if (!root || !selector) return null;
        let direct = null;
        try { if (root.querySelector) direct = root.querySelector(selector); } catch (err) { err.code = "SELECTOR_INVALID"; throw err; }
        if (direct) return direct;
        if (opt.deep_shadow === false) return null;
        const all = root.querySelectorAll ? root.querySelectorAll("*") : [];
        for (const el of all) {
            if (el && el.shadowRoot) {
                const found = queryDeep(el.shadowRoot, selector, opt);
                if (found) return found;
            }
        }
        return null;
    }
    function queryAllDeep(root, selector, opt, out) {
        opt = opt || {}; out = out || [];
        if (!root || !selector) return out;
        try { if (root.querySelectorAll) Array.prototype.forEach.call(root.querySelectorAll(selector), function (el) { out.push(el); }); } catch (err) { err.code = "SELECTOR_INVALID"; throw err; }
        if (opt.deep_shadow === false) return out;
        const all = root.querySelectorAll ? root.querySelectorAll("*") : [];
        Array.prototype.forEach.call(all, function (el) { if (el && el.shadowRoot) queryAllDeep(el.shadowRoot, selector, opt, out); });
        return out;
    }
    function setText(el, value) {
        const v = safeString(value);
        if (!el) throw new Error("ELEMENT_MISSING");
        if (el.disabled || el.getAttribute("aria-disabled") === "true") throw new Error("INPUT_DISABLED");
        const tag = safeString(el.tagName).toLowerCase();
        const editable = el.isContentEditable || safeString(el.getAttribute && el.getAttribute("contenteditable")).toLowerCase() === "true" || tag === "div";
        try { el.focus && el.focus(); } catch (err) {}
        if (editable && !("value" in el)) {
            try {
                const sel = window.getSelection && window.getSelection();
                const range = document.createRange && document.createRange();
                if (sel && range) { range.selectNodeContents(el); range.deleteContents(); sel.removeAllRanges(); sel.addRange(range); }
            } catch (err) {}
            try { el.dispatchEvent(new InputEvent("beforeinput", { bubbles: true, cancelable: true, composed: true, inputType: "insertText", data: v })); } catch (err) {}
            try { document.execCommand && document.execCommand("insertText", false, v); } catch (err) { el.innerText = v; el.textContent = v; }
            if (!safeString(el.innerText || el.textContent).trim() && v) { el.innerText = v; el.textContent = v; }
        } else if (tag === "input" || tag === "textarea" || tag === "select" || "value" in el) {
            el.value = v;
        } else {
            el.textContent = v;
        }
        try { el.dispatchEvent(new InputEvent("input", { bubbles: true, cancelable: true, composed: true, inputType: "insertText", data: v })); } catch (err) { try { el.dispatchEvent(new Event("input", { bubbles: true, composed: true })); } catch (e) {} }
        try { el.dispatchEvent(new Event("change", { bubbles: true, composed: true })); } catch (err) {}
        try { el.focus && el.focus(); } catch (err) {}
    }
    function clickEl(el) {
        if (!el) throw new Error("ELEMENT_MISSING");
        if (el.disabled || el.getAttribute("aria-disabled") === "true") throw new Error("BUTTON_DISABLED");
        try { el.scrollIntoView && el.scrollIntoView({ block: "center", inline: "center" }); } catch (err) {}
        try { el.focus && el.focus(); } catch (err) {}
        ["mousedown", "mouseup", "click"].forEach(function (t) { try { el.dispatchEvent(new MouseEvent(t, { bubbles: true, cancelable: true, composed: true, view: window })); } catch (err) {} });
        try { el.click(); } catch (err) {}
    }
    function pressEnter(el) {
        if (!el) throw new Error("ELEMENT_MISSING");
        try { el.focus && el.focus(); } catch (err) {}
        ["keydown", "keypress", "keyup"].forEach(function (type) { try { el.dispatchEvent(new KeyboardEvent(type, { key: "Enter", code: "Enter", keyCode: 13, which: 13, bubbles: true, cancelable: true, composed: true })); } catch (err) {} });
    }
    function makeWindow(panel, key) {
        const restoreId = key + "_restore";
        const title = panel.querySelector("[data-aiwk-win-title]") || panel.firstElementChild;
        panel.style.resize = "both";
        panel.style.overflow = "auto";
        const saved = (() => { try { return JSON.parse(localStorage.getItem(key) || "null"); } catch (err) { return null; } })();
        if (saved) {
            if (saved.left !== undefined) { panel.style.left = saved.left + "px"; panel.style.right = "auto"; }
            if (saved.top !== undefined) { panel.style.top = saved.top + "px"; panel.style.bottom = "auto"; }
            if (saved.width) panel.style.width = saved.width + "px";
            if (saved.height) panel.style.height = saved.height + "px";
        }
        function persist() {
            try {
                const r = panel.getBoundingClientRect();
                localStorage.setItem(key, JSON.stringify({ left: Math.round(r.left), top: Math.round(r.top), width: Math.round(r.width), height: Math.round(r.height) }));
            } catch (err) {}
        }
        if (title) {
            title.style.cursor = "move";
            title.addEventListener("mousedown", function (ev) {
                if (ev.button !== 0 || ev.target.closest("button,input,textarea,select,a")) return;
                ev.preventDefault();
                const r = panel.getBoundingClientRect();
                const sx = ev.clientX, sy = ev.clientY, sl = r.left, st = r.top;
                panel.style.left = sl + "px"; panel.style.top = st + "px"; panel.style.right = "auto"; panel.style.bottom = "auto";
                function move(e) { panel.style.left = Math.max(0, sl + e.clientX - sx) + "px"; panel.style.top = Math.max(0, st + e.clientY - sy) + "px"; }
                function up() { document.removeEventListener("mousemove", move, true); document.removeEventListener("mouseup", up, true); persist(); }
                document.addEventListener("mousemove", move, true); document.addEventListener("mouseup", up, true);
            }, true);
        }
        let restore = document.getElementById(restoreId);
        if (!restore) {
            restore = document.createElement("button");
            restore.id = restoreId;
            restore.type = "button";
            restore.textContent = "AIWK selector";
            restore.style.cssText = "position:fixed;right:8px;bottom:42px;z-index:2147483647;background:#111827;color:#fff;border:1px solid #60a5fa;border-radius:999px;padding:4px 8px;font:12px Arial;display:none;cursor:pointer";
            restore.addEventListener("click", function () { panel.style.display = "block"; restore.style.display = "none"; });
            (document.body || document.documentElement).appendChild(restore);
        }
        panel.__aiwkHideToButton = function () { panel.style.display = "none"; restore.style.display = "block"; persist(); };
        panel.__aiwkDestroy = function () { try { panel.remove(); } catch (err) {} try { restore.remove(); } catch (err) {} };
    }
    function log(panel, text) {
        const el = panel && panel.querySelector("[data-aiwk-selector-log]");
        if (!el) return;
        const line = document.createElement("div");
        line.textContent = nowText() + " " + safeString(text).slice(0, 1200);
        el.appendChild(line);
        while (el.children.length > 40) el.removeChild(el.firstChild);
        el.scrollTop = el.scrollHeight;
    }
    function values(panel) {
        const q = function (sel) { const el = panel.querySelector(sel); return el ? safeString(el.value).trim() : ""; };
        const c = function (sel) { const el = panel.querySelector(sel); return !!(el && el.checked); };
        return { selector: q("[data-aiwk-selector]"), value: (panel.querySelector("[data-aiwk-selector-value]") || {}).value || "", deep_shadow: c("[data-aiwk-deep-shadow]") };
    }
    function run(panel, action) {
        const v = values(panel);
        if (!v.selector) { log(panel, "ERR SELECTOR_EMPTY / 해결: selector 입력"); return; }
        let el;
        try { el = queryDeep(document, v.selector, { deep_shadow: v.deep_shadow }); } catch (err) { log(panel, "ERR SELECTOR_INVALID " + (err.message || err)); return; }
        if (!el && action !== "count") { log(panel, "ERR SELECTOR_NOT_FOUND " + v.selector); return; }
        try {
            if (action === "find") log(panel, "OK FOUND " + JSON.stringify(describe(el)));
            else if (action === "count") log(panel, "OK COUNT " + queryAllDeep(document, v.selector, { deep_shadow: v.deep_shadow }).length);
            else if (action === "input") { setText(el, v.value); log(panel, "OK INPUT " + JSON.stringify(describe(el))); }
            else if (action === "click") { clickEl(el); log(panel, "OK CLICK " + JSON.stringify(describe(el))); }
            else if (action === "enter") { pressEnter(el); log(panel, "OK ENTER " + v.selector); }
            else if (action === "input_enter") { setText(el, v.value); pressEnter(el); log(panel, "OK INPUT_ENTER " + v.selector); }
            else if (action === "text") log(panel, "OK TEXT " + safeString(el.innerText || el.textContent || ""));
            else if (action === "html") log(panel, "OK HTML " + safeString(el.innerHTML || "").slice(0, 3000));
        } catch (err) { log(panel, "ERR " + action + " " + (err && err.message ? err.message : String(err))); }
    }
    function ensurePanel() {
        let panel = document.getElementById("aiwk_selector_tool_module_panel");
        if (panel) { panel.style.display = "block"; return panel; }
        panel = document.createElement("div");
        panel.id = "aiwk_selector_tool_module_panel";
        panel.setAttribute("data-aiwk-module-window", "1");
        panel.setAttribute("data-aiwk-window-label", "AIWK selector");
        panel.setAttribute("data-aiwk-module-id", MODULE_ID);
        panel.style.cssText = "position:fixed;left:8px;top:70px;z-index:2147483647;width:330px;max-width:92vw;max-height:80vh;background:rgba(17,24,39,.97);color:#fff;font:12px/1.35 Arial,sans-serif;border:1px solid #60a5fa;border-radius:8px;box-shadow:0 2px 14px rgba(0,0,0,.4);padding:7px;user-select:text;box-sizing:border-box;";
        panel.innerHTML = [
            '<div data-aiwk-win-title="1" style="display:flex;gap:6px;align-items:center;margin-bottom:5px;"><b>AIWK Selector Tool</b><span style="margin-left:auto;color:#93c5fd;">v123</span><button type="button" data-aiwk-hide="1" style="background:#374151;color:#fff;border:0;border-radius:4px;padding:1px 5px;cursor:pointer;">×</button></div>',
            '<div style="color:#d1d5db;word-break:break-all;max-height:30px;overflow:hidden;margin-bottom:4px;">' + safeString(location.hostname || location.href) + '</div>',
            '<label style="display:block;color:#facc15;font-size:11px;">selector</label><input data-aiwk-selector="1" value="#input" style="box-sizing:border-box;width:100%;margin:0 0 4px;background:#030712;color:#fff;border:1px solid #4b5563;border-radius:4px;padding:4px;font:12px monospace;">',
            '<label style="display:block;color:#facc15;font-size:11px;">value</label><textarea data-aiwk-selector-value="1" style="box-sizing:border-box;width:100%;height:44px;resize:vertical;margin:0 0 4px;background:#030712;color:#fff;border:1px solid #4b5563;border-radius:4px;padding:4px;font:12px Arial;"></textarea>',
            '<label style="display:flex;gap:4px;align-items:center;color:#d1d5db;margin-bottom:4px;"><input type="checkbox" data-aiwk-deep-shadow="1" checked> deep shadow</label>',
            '<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:4px;"><button data-aiwk-act="find">찾기</button><button data-aiwk-act="count">개수</button><button data-aiwk-act="input">입력</button><button data-aiwk-act="enter">Enter</button><button data-aiwk-act="input_enter">입력+Enter</button><button data-aiwk-act="click">클릭</button><button data-aiwk-act="text">텍스트</button><button data-aiwk-act="html">HTML</button></div>',
            '<div data-aiwk-selector-log="1" style="max-height:140px;overflow:auto;background:rgba(0,0,0,.32);border:1px solid #374151;border-radius:4px;padding:3px;color:#d1d5db;font:11px/1.25 monospace;"></div>'
        ].join("");
        (document.body || document.documentElement).appendChild(panel);
        Array.prototype.forEach.call(panel.querySelectorAll("button[data-aiwk-act]"), function (b) { b.style.cssText = "background:#2563eb;color:#fff;border:0;border-radius:4px;padding:3px 6px;cursor:pointer;"; });
        panel.addEventListener("click", function (ev) {
            const t = ev.target;
            if (!t) return;
            if (t.getAttribute("data-aiwk-hide")) { if (panel.__aiwkHideToButton) panel.__aiwkHideToButton(); else panel.style.display = "none"; return; }
            const act = t.getAttribute("data-aiwk-act");
            if (act) run(panel, act);
        });
        makeWindow(panel, "AIWK_WIN::selector_tool::" + (location.hostname || "unknown"));
        log(panel, "module loaded " + VERSION + " / 체크 해제 후 선택모듈 실행 또는 해제저장하면 제거됩니다");
        sendEvent("selector_tool_ready", { panel_id: panel.id, version: VERSION });
        return panel;
    }
    function destroy() {
        const panel = document.getElementById("aiwk_selector_tool_module_panel");
        if (panel && panel.__aiwkDestroy) panel.__aiwkDestroy();
        else if (panel) panel.remove();
        window.__AIWK_CORE_SELECTOR_TOOL_V118__ = false;
        sendEvent("selector_tool_destroy", {});
    }
    window.addEventListener("AIWK_MODULE_UNLOAD", function (ev) {
        const id = ev && ev.detail && ev.detail.module_id;
        if (!id || id === MODULE_ID || id === "*") destroy();
    });
    ensurePanel();
}());
