// /AIWK_COMMON/modules/dev/js_runner.js
// AIWK EXT4 v123-binding-state-label-hotfix
(function () {
    "use strict";

    const AIWK = window.AIWK;

    function el(tag, className, text) {
        const node = document.createElement(tag);
        if (className) node.className = className;
        if (text !== undefined) node.textContent = text;
        return node;
    }

    function pretty(obj) {
        return JSON.stringify(obj, null, 2);
    }

    function parseJson(text, fallback) {
        const s = String(text || "").trim();
        if (!s) return fallback;
        return JSON.parse(s);
    }

    function currentTabId() {
        try {
            const st = AIWK.comm && typeof AIWK.comm.status === "function" ? AIWK.comm.status() : null;
            return st && st.tab_id ? String(st.tab_id) : "";
        } catch (err) {
            return "";
        }
    }

    function makeInput(id, value, placeholder) {
        const node = document.createElement("input");
        node.id = id;
        node.className = "aiwk-textarea px-2 py-1 rounded border";
        node.value = value || "";
        node.placeholder = placeholder || "";
        return node;
    }

    function makeTextarea(id, rows, value, placeholder) {
        const node = document.createElement("textarea");
        node.id = id;
        node.className = "aiwk-textarea px-2 py-1 rounded border";
        node.rows = rows || 1;
        node.value = value || "";
        node.placeholder = placeholder || "";
        return node;
    }

    async function runtimeMessage(msg) {
        if (!chrome || !chrome.runtime || !chrome.runtime.sendMessage) {
            throw new Error("CHROME_RUNTIME_MISSING");
        }
        return await chrome.runtime.sendMessage(msg);
    }

    AIWK.modules.register("dev.js_runner", {
        name: "dev.js_runner",
        run: async function (ctx) {
            return {
                ok: 1,
                module: "dev.js_runner",
                win_id: ctx.win.id,
                role: AIWK.auth.role,
                message: "dev.js_runner v123 ready",
                received: ctx.msg || {}
            };
        },
        test: async function (ctx) {
            if (!AIWK.auth.can("dev")) {
                return { ok: 1, module: "dev.js_runner", win_id: ctx.win.id, mode: "locked", role: AIWK.auth.role, message: "dev role required for execution; UI loaded" };
            }
            return { ok: 1, module: "dev.js_runner", win_id: ctx.win.id, mode: "dev", role: AIWK.auth.role, message: "js runner iframe selector selftest completed" };
        },
        mount: function (ctx) {
            const box = el("div", "space-y-2 text-sm aiwk-js-runner select-text");
            const title = el("div", "text-base font-semibold select-text", "JS Runner / 선택자/iframe agent chat/stream v123");
            const desc = el("div", "text-xs select-text", "BUS/JS 실행은 유지하고, iframe 내부 선택자는 frame_bridge + tab_id 기준 service_worker 라우팅으로 실행합니다. 실행은 dev 권한에서만 허용합니다.");

            const target = makeInput("aiwk-js-runner-target", "auth-win", "target win id 예: auth-win");
            const action = makeInput("aiwk-js-runner-action", "너의 기능은?", "명령 예: 너의 기능은? / 너의 사용법은? / 셀프테스트 해라!");
            const payload = makeTextarea("aiwk-js-runner-payload", 3, '{\n  "source": "js-runner",\n  "check": "v123"\n}', "payload JSON");
            const code = makeTextarea("aiwk-js-runner-code", 7, "return await BUS.ask(target, action, payload);", "함수 본문 형식. 사용 가능 변수: AIWK, BUS, target, action, payload, win");

            const selectorTitle = el("div", "text-sm font-semibold select-text", "선택자 / iframe 실행");
            const selectorDesc = el("div", "text-xs select-text", "frame_id를 비워두면 top 문서에서 찾고, frame URL 포함값 또는 iframe selector를 넣으면 해당 iframe 내부 content script에서 찾습니다.");
            const tabId = makeInput("aiwk-selector-tab-id", currentTabId(), "target tab_id 비우면 활성 탭");
            const frameId = makeInput("aiwk-selector-frame-id", "", "frame_id 예: 0 / 비우면 자동");
            const frameUrl = makeInput("aiwk-selector-frame-url", "", "frame URL 포함값 예: example.com/frame");
            const iframeSelector = makeInput("aiwk-selector-iframe-selector", "", "iframe selector 예: iframe#chatframe");
            const selector = makeInput("aiwk-selector-selector", "#input", "실제 selector 예: #input / textarea / [contenteditable='true']");
            const value = makeTextarea("aiwk-selector-value", 2, "하이", "input 값");

            const actions = el("div", "flex flex-wrap gap-1 select-text");
            function btn(label, mode) {
                const b = document.createElement("button");
                b.type = "button";
                b.className = "aiwk-btn";
                b.dataset.jsRunnerAction = mode;
                b.textContent = label;
                return b;
            }
            actions.appendChild(btn("BUS 실행", "bus"));
            actions.appendChild(btn("JS 형식 실행", "code"));
            actions.appendChild(btn("사용 예 넣기", "sample"));
            actions.appendChild(btn("프레임목록", "frames"));
            actions.appendChild(btn("iframe agent목록", "agent_list"));
            actions.appendChild(btn("iframe probe", "agent_probe"));
            actions.appendChild(btn("iframe chat입력", "agent_chat_input"));
            actions.appendChild(btn("iframe chat전송", "agent_chat_send"));
            actions.appendChild(btn("선택자찾기", "selector_find"));
            actions.appendChild(btn("선택자클릭", "selector_click"));
            actions.appendChild(btn("선택자입력", "selector_input"));
            actions.appendChild(btn("선택자텍스트", "selector_text"));
            actions.appendChild(btn("iframe 예", "selector_sample"));
            actions.appendChild(btn("결과 복사", "copy"));
            actions.appendChild(btn("결과 지우기", "clear"));

            const result = el("pre", "aiwk-run-result select-text", "대상 창과 명령을 입력한 뒤 BUS 실행 또는 프레임목록을 누르십시오.");
            result.id = "aiwk-js-runner-result";

            function print(obj) {
                result.textContent = typeof obj === "string" ? obj : pretty(obj);
                result.scrollTop = result.scrollHeight;
                if (window.AIWK_LOG && typeof window.AIWK_LOG.appendResult === "function") {
                    window.AIWK_LOG.appendResult("JS RUNNER", obj);
                }
                ctx.status.textContent = "js runner ready";
            }

            function requireDev() {
                if (!AIWK.auth.can("dev")) {
                    throw new Error("DEV_REQUIRED: JS/선택자 실행은 dev 권한에서만 허용됩니다.");
                }
            }

            function selectorRequest(actionName) {
                const tid = String(tabId.value || "").trim();
                const fid = String(frameId.value || "").trim();
                const furl = String(frameUrl.value || "").trim();
                const ifsel = String(iframeSelector.value || "").trim();
                const req = {
                    type: "AIWK_SELECTOR_RUN",
                    target_tab_id: tid,
                    action: actionName,
                    selector: String(selector.value || "").trim(),
                    value: String(value.value || ""),
                    deep_shadow: true
                };
                if (fid) req.frame_id = fid;
                if (furl) req.frame_url_contains = furl;
                if (ifsel) req.iframe_selector = ifsel;
                return req;
            }

            actions.addEventListener("click", function (ev) {
                const b = ev.target.closest("button[data-js-runner-action]");
                if (!b) return;
                ev.preventDefault();
                ev.stopPropagation();
                const mode = b.dataset.jsRunnerAction;
                (async function () {
                    try {
                        if (mode === "sample") {
                            target.value = "auth-win";
                            action.value = "너의 사용법은?";
                            payload.value = '{\n  "source": "js-runner",\n  "check": "v123",\n  "mode": "sample"\n}';
                            code.value = "const a = await BUS.ask(target, '너의 기능은?', payload);\nconst h = await BUS.ask(target, '너의 사용법은?', payload);\nreturn { ok: 1, target, 기능: a, 사용법: h };";
                            print("사용 예를 넣었습니다.");
                            return;
                        }
                        if (mode === "selector_sample") {
                            tabId.value = currentTabId();
                            frameId.value = "";
                            frameUrl.value = "example.com/frame";
                            iframeSelector.value = "iframe#chatframe";
                            selector.value = "#input";
                            value.value = "하이";
                            print("iframe 선택자 예를 넣었습니다. 먼저 [프레임목록]으로 frame_id와 href를 확인하십시오.");
                            return;
                        }
                        if (mode === "copy") {
                            await navigator.clipboard.writeText(result.textContent || "");
                            ctx.status.textContent = "copied";
                            return;
                        }
                        if (mode === "clear") {
                            result.textContent = "";
                            ctx.status.textContent = "cleared";
                            return;
                        }
                        requireDev();
                        const t = String(target.value || "").trim();
                        const a = String(action.value || "").trim() || "help";
                        const p = parseJson(payload.value, {});
                        if (mode === "bus") {
                            if (!window.AIWK_BUS || typeof window.AIWK_BUS.ask !== "function") {
                                throw new Error("AIWK_BUS_MISSING: BUS가 없습니다.");
                            }
                            print(await window.AIWK_BUS.ask(t, a, p));
                            return;
                        }
                        if (mode === "code") {
                            if (!window.AIWK_BUS) {
                                throw new Error("AIWK_BUS_MISSING: BUS가 없습니다.");
                            }
                            const body = String(code.value || "");
                            const fn = new Function("AIWK", "BUS", "target", "action", "payload", "win", "return (async function(){\n" + body + "\n}).call(win);");
                            print(await fn(AIWK, window.AIWK_BUS, t, a, p, ctx.win));
                            return;
                        }
                        if (mode === "frames") {
                            print(await runtimeMessage({ type: "AIWK_SELECTOR_LIST_FRAMES", target_tab_id: String(tabId.value || "").trim() }));
                            return;
                        }
                        if (mode === "agent_list") {
                            print(await runtimeMessage({ type: "AIWK_IFRAME_AGENT_LIST", target_tab_id: String(tabId.value || "").trim() }));
                            return;
                        }
                        if (mode === "agent_probe") {
                            const req = {
                                type: "AIWK_IFRAME_AGENT_PROBE",
                                target_tab_id: String(tabId.value || "").trim(),
                                probe_text: String(value.value || "AIWK iframe agent probe"),
                                source: "dev.js_runner"
                            };
                            if (String(frameId.value || "").trim()) req.frame_id = String(frameId.value || "").trim();
                            if (String(frameUrl.value || "").trim()) req.frame_url_contains = String(frameUrl.value || "").trim();
                            if (String(iframeSelector.value || "").trim()) req.iframe_selector = String(iframeSelector.value || "").trim();
                            print(await runtimeMessage(req));
                            return;
                        }
                        if (mode === "agent_chat_input" || mode === "agent_chat_send") {
                            const req = {
                                type: "AIWK_IFRAME_AGENT_CHAT_SEND",
                                target_tab_id: String(tabId.value || "").trim(),
                                selector: String(selector.value || "#input").trim(),
                                send_selector: "#send-button",
                                value: String(value.value || ""),
                                click_send: mode === "agent_chat_send",
                                source: "dev.js_runner"
                            };
                            if (String(frameId.value || "").trim()) req.frame_id = String(frameId.value || "").trim();
                            if (String(frameUrl.value || "").trim()) req.frame_url_contains = String(frameUrl.value || "").trim();
                            if (String(iframeSelector.value || "").trim()) req.iframe_selector = String(iframeSelector.value || "").trim();
                            print(await runtimeMessage(req));
                            return;
                        }
                        if (mode.indexOf("selector_") === 0) {
                            const actionName = mode.replace("selector_", "");
                            print(await runtimeMessage(selectorRequest(actionName)));
                            return;
                        }
                    } catch (err) {
                        print({ ok: 0, error: err && err.message ? err.message : String(err), mode: mode });
                        ctx.status.textContent = "ERROR";
                    }
                }());
            });

            try {
                ctx.win.offJsRunnerTarget = AIWK.events.on("js-runner:target", function (data) {
                    if (data && data.target_win_id) target.value = data.target_win_id;
                });
            } catch (err) {}

            box.appendChild(title);
            box.appendChild(desc);
            box.appendChild(el("div", "text-xs font-semibold select-text", "대상 창"));
            box.appendChild(target);
            box.appendChild(el("div", "text-xs font-semibold select-text", "명령"));
            box.appendChild(action);
            box.appendChild(el("div", "text-xs font-semibold select-text", "payload JSON"));
            box.appendChild(payload);
            box.appendChild(el("div", "text-xs font-semibold select-text", "JS 함수 본문"));
            box.appendChild(code);
            box.appendChild(selectorTitle);
            box.appendChild(selectorDesc);
            box.appendChild(el("div", "text-xs font-semibold select-text", "target tab_id"));
            box.appendChild(tabId);
            box.appendChild(el("div", "text-xs font-semibold select-text", "frame_id / frame URL 포함 / iframe selector"));
            box.appendChild(frameId);
            box.appendChild(frameUrl);
            box.appendChild(iframeSelector);
            box.appendChild(el("div", "text-xs font-semibold select-text", "selector / input 값"));
            box.appendChild(selector);
            box.appendChild(value);
            box.appendChild(actions);
            box.appendChild(result);
            ctx.body.appendChild(box);
            ctx.status.textContent = "v123 JS runner selector/iframe agent chat/stream ready";
        }
    });
}());
