// /AIWK_COMMON/action_ui/aiwk_action_ui_basic.js
// AIWK EXT4 v051 · action별 URI 실행창 UI 기본 registry + 공통 채팅/대상/반복 ping UI
(function () {
    "use strict";

    const ROOT = window;
    const UI = ROOT.AIWK_ACTION_UI = ROOT.AIWK_ACTION_UI || {};
    const LOOP_KEY = "AIWK_URI_PING_LOOP_ENABLED_V1";
    const LOOP_MS_KEY = "AIWK_URI_PING_LOOP_MS_V1";

    function esc(v) {
        return String(v === undefined || v === null ? "" : v)
            .replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\"/g, "&quot;");
    }
    function json(v) { try { return JSON.stringify(v || {}, null, 2); } catch (err) { return String(v); } }
    function firstText(ctx) {
        const p = ctx.parsed || {};
        const q = p.query || {};
        const pl = p.payload || {};
        return String(pl.text || q.text || q.message || q.chat || "");
    }
    function getLoopEnabled() {
        try { return localStorage.getItem(LOOP_KEY) === "1"; } catch (err) { return false; }
    }
    function getLoopMs() {
        try { return Math.max(500, parseInt(localStorage.getItem(LOOP_MS_KEY) || "3000", 10) || 3000); } catch (err) { return 3000; }
    }
    function setLoop(enabled, ms) {
        try {
            localStorage.setItem(LOOP_KEY, enabled ? "1" : "0");
            localStorage.setItem(LOOP_MS_KEY, String(Math.max(500, parseInt(ms || 3000, 10) || 3000)));
        } catch (err) {}
    }
    function targetAddress(p) {
        if (ROOT.AIWK && AIWK.protocol && AIWK.protocol.endpointAddress) {
            return AIWK.protocol.endpointAddress(p.group || "home", p.project || "IG_CRM", p.client_id || p.to || "C1", p.endpoint || p.to_endpoint || "ext4");
        }
        return [p.group || "home", p.project || "IG_CRM", p.client_id || p.to || "C1"].join(".") + "#" + (p.endpoint || p.to_endpoint || "ext4");
    }
    function parseTargetLine(v, p) {
        v = String(v || "").trim();
        p = p || {};
        if (!v) return p;
        if (/^aiwk:\/\//i.test(v) && ROOT.AIWK && AIWK.protocol && AIWK.protocol.parseUri) {
            const u = AIWK.protocol.parseUri(v);
            if (u.ok) {
                p.group = u.group; p.project = u.project; p.client_id = u.client_id; p.to = u.client_id; p.endpoint = u.endpoint; p.to_endpoint = u.endpoint; p.room_id = u.room_id || p.room_id;
            }
            return p;
        }
        const h = v.indexOf("#");
        const endpoint = h >= 0 ? v.slice(h + 1).trim() : "";
        const base = h >= 0 ? v.slice(0, h).trim() : v;
        const host = base.indexOf("@") >= 0 ? base.slice(base.lastIndexOf("@") + 1) : base;
        const parts = host.split(".").filter(Boolean);
        if (parts.length >= 3) {
            p.group = parts[0];
            p.project = parts[1];
            p.client_id = parts.slice(2).join(".");
            p.to = p.client_id;
        } else if (parts.length === 1) {
            p.client_id = parts[0];
            p.to = p.client_id;
        }
        if (endpoint) { p.endpoint = endpoint; p.to_endpoint = endpoint; }
        return p;
    }

    function baseRows(ctx) {
        const p = ctx.parsed || {};
        return [
            '<div class="aiwk-uri-source">EXT4 Content Script Runner · 웹페이지 DOM 위에 삽입된 EXT4 실행창입니다.</div>',
            '<div class="aiwk-uri-row"><b>URI</b><code>' + esc((p.uri || "").replace(p.token || "", p.token ? (p.token_masked || "***") : "")) + '</code></div>',
            '<div class="aiwk-uri-grid">',
            '<label>group<input data-aiwk-group value="' + esc(p.group || "") + '"></label>',
            '<label>project<input data-aiwk-project value="' + esc(p.project || "") + '"></label>',
            '<label>room_id <span style="font-size:11px;color:#fbbf24;">인증/표시용</span><input data-aiwk-room value="' + esc(p.room_id || "") + '"></label>',
            '<label>token <span style="font-size:11px;color:#fbbf24;">URI 입력값은 저장용</span><input data-aiwk-token value="' + esc(p.token_masked || "") + '" disabled></label>',
            '<label>action<input data-aiwk-action value="' + esc(p.action || "") + '"></label>',
            '<label>timeout_ms<input data-aiwk-timeout value="' + esc(p.timeout_ms || 10000) + '"></label>',
            '</div>',
            '<div class="aiwk-uri-row"><b>대상(to) · 채팅창 바로 위에서 항상 수정</b><input data-aiwk-to-address value="' + esc(targetAddress(p)) + '" style="box-sizing:border-box;width:100%;background:#020617;color:#f9fafb;border:1px solid rgba(255,255,255,.16);border-radius:8px;padding:8px;"></div>',
            '<div class="aiwk-uri-row"><b>payload</b><pre data-aiwk-payload>' + esc(json(p.payload || {})) + '</pre></div>'
        ].join("");
    }

    function chatBox(ctx, placeholder) {
        return '<div class="aiwk-uri-row"><b>채팅 / JSON 명령</b><textarea data-aiwk-chat-text placeholder="' + esc(placeholder || '그냥 텍스트면 aiwk_chat, JSON이면 type/action/to/payload 반영') + '">' + esc(firstText(ctx)) + '</textarea></div>';
    }

    function loopBox() {
        return [
            '<div class="aiwk-uri-loop">',
            '<label><input type="checkbox" data-aiwk-ping-loop ' + (getLoopEnabled() ? 'checked' : '') + '> 반복 Ping/Pong 허용/실행</label>',
            '<label>주기(ms)<input data-aiwk-ping-loop-ms value="' + esc(getLoopMs()) + '"></label>',
            '<div class="aiwk-uri-loop-note">반복은 양쪽 client가 모두 체크되어 있을 때만 계속됩니다. 상대가 미허용이면 1회 후 중지합니다.</div>',
            '</div>'
        ].join("");
    }

    function commonBeforeSend(ctx, parsed) {
        parsed = parsed || {};
        const body = ctx.body || document;
        const toLine = body.querySelector('[data-aiwk-to-address]');
        const action = body.querySelector('[data-aiwk-action]');
        const group = body.querySelector('[data-aiwk-group]');
        const project = body.querySelector('[data-aiwk-project]');
        const room = body.querySelector('[data-aiwk-room]');
        const timeout = body.querySelector('[data-aiwk-timeout]');
        const txt = body.querySelector('[data-aiwk-chat-text]');
        const loop = body.querySelector('[data-aiwk-ping-loop]');
        const loopMs = body.querySelector('[data-aiwk-ping-loop-ms]');
        if (group) parsed.group = group.value.trim() || "home";
        if (project) parsed.project = project.value.trim() || "IG_CRM";
        if (room) parsed.room_id = room.value.trim();
        if (action) parsed.action = action.value.trim() || "aiwk_chat";
        if (timeout) parsed.timeout_ms = Math.max(500, parseInt(timeout.value || 10000, 10) || 10000);
        if (toLine) parsed = parseTargetLine(toLine.value, parsed);
        if (loop) {
            const ms = loopMs ? loopMs.value : getLoopMs();
            setLoop(!!loop.checked, ms);
            parsed.payload = Object.assign({}, parsed.payload || {}, {
                loop_request: !!loop.checked,
                loop_ms: Math.max(500, parseInt(ms || 3000, 10) || 3000)
            });
        }
        const raw = txt ? String(txt.value || "").trim() : "";
        const currentAction = String(parsed.action || "aiwk_chat").trim() || "aiwk_chat";
        if (!raw) {
            if (!parsed.payload) parsed.payload = {};
            if (currentAction !== "aiwk_chat") parsed.type = parsed.type || "command";
            return parsed;
        }
        if (/^[\[{]/.test(raw)) {
            try {
                const obj = JSON.parse(raw);
                if (obj.type) parsed.type = obj.type;
                if (obj.action) parsed.action = obj.action;
                if (obj.to) parseTargetLine(obj.to, parsed);
                if (obj.to_client) { parsed.to = obj.to_client; parsed.client_id = obj.to_client; }
                if (obj.to_endpoint) { parsed.to_endpoint = obj.to_endpoint; parsed.endpoint = obj.to_endpoint; }
                if (obj.endpoint) { parsed.to_endpoint = obj.endpoint; parsed.endpoint = obj.endpoint; }
                if (obj.payload !== undefined) parsed.payload = Object.assign({}, parsed.payload || {}, obj.payload || {});
                else parsed.payload = Object.assign({}, parsed.payload || {}, obj || {});
                if (obj.room_id !== undefined) parsed.room_id = obj.room_id;
                if (obj.group) parsed.group = obj.group;
                if (obj.project) parsed.project = obj.project;
                if (!parsed.type) parsed.type = parsed.action === "aiwk_chat" ? "chat" : "command";
                return parsed;
            } catch (err) {
                if (currentAction === "aiwk_chat") {
                    parsed.type = "chat";
                    parsed.action = "aiwk_chat";
                    parsed.payload = { text: raw, parse_error: err.message || String(err) };
                } else {
                    parsed.type = parsed.type || "command";
                    parsed.action = currentAction;
                    parsed.payload = Object.assign({}, parsed.payload || {}, { text: raw, parse_error: err.message || String(err) });
                }
                return parsed;
            }
        }
        if (currentAction === "aiwk_chat") {
            parsed.type = "chat";
            parsed.action = "aiwk_chat";
            parsed.payload = Object.assign({}, parsed.payload || {}, { text: raw });
        } else {
            parsed.type = parsed.type || "command";
            parsed.action = currentAction;
            parsed.payload = Object.assign({}, parsed.payload || {}, { text: raw });
        }
        return parsed;
    }

    function commonResult(prefix) {
        return function (ctx, msg, meta) {
            const box = ctx.resultBox;
            if (!box) return;
            box.textContent = '[' + new Date().toLocaleTimeString() + '] ' + prefix + (meta && meta.latency_ms !== undefined ? ' / latency=' + meta.latency_ms + 'ms' : '') + '\n' + json(msg || {});
        };
    }

    function defaultRender(ctx) {
        return [baseRows(ctx), chatBox(ctx), '<div class="aiwk-uri-actions"><button type="button" data-aiwk-run="1">전송</button><button type="button" data-aiwk-cancel="1">닫기</button></div>', '<pre class="aiwk-uri-result" data-aiwk-result>대기 중</pre>'].join("");
    }

    UI._default = UI._default || {
        title: "AIWK URI 실행창",
        confirm_required: true,
        render: defaultRender,
        beforeSend: commonBeforeSend,
        onResult: commonResult("결과 수신")
    };

    UI.aiwk_chat = {
        title: "AIWK Chat",
        confirm_required: true,
        render: function (ctx) {
            return [
                '<div class="aiwk-uri-title-note">기본은 채팅입니다. 대상(to)을 바로 수정하고 텍스트 또는 JSON을 보낼 수 있습니다.</div>',
                baseRows(ctx),
                chatBox(ctx, '예: 안녕 / 또는 {"action":"aiwk_status","payload":{}}'),
                '<div class="aiwk-uri-actions"><button type="button" data-aiwk-run="1">채팅 전송</button><button type="button" data-aiwk-cancel="1">닫기</button></div>',
                '<pre class="aiwk-uri-result" data-aiwk-result>전송 전</pre>'
            ].join("");
        },
        beforeSend: commonBeforeSend,
        onResult: commonResult("CHAT ACK")
    };

    UI.aiwk_ping = {
        title: "AIWK Ping",
        confirm_required: true,
        render: function (ctx) {
            return [
                '<div class="aiwk-uri-title-note">대상 client가 직접 <b>aiwk_pong</b>으로 회신해야 latency가 표시됩니다.</div>',
                baseRows(ctx),
                chatBox(ctx, '선택: ping과 함께 보낼 메모 또는 JSON'),
                loopBox(),
                '<div class="aiwk-uri-actions"><button type="button" data-aiwk-run="1">Ping 실행</button><button type="button" data-aiwk-cancel="1">닫기</button></div>',
                '<pre class="aiwk-uri-result" data-aiwk-result>Ping 실행 전</pre>'
            ].join("");
        },
        beforeSend: commonBeforeSend,
        onResult: commonResult("PONG")
    };

    UI.aiwk_route = {
        title: "AIWK Route",
        confirm_required: true,
        render: function (ctx) {
            return [
                '<div class="aiwk-uri-title-note">Hub 자동 응답이 아니라 대상 client가 받은 route 정보를 직접 회신합니다.</div>',
                baseRows(ctx),
                chatBox(ctx, '선택: route 확인과 함께 보낼 메모 또는 JSON'),
                '<div class="aiwk-uri-actions"><button type="button" data-aiwk-run="1">Route 확인</button><button type="button" data-aiwk-cancel="1">닫기</button></div>',
                '<pre class="aiwk-uri-result" data-aiwk-result>Route 실행 전</pre>'
            ].join("");
        },
        beforeSend: commonBeforeSend,
        onResult: commonResult("ROUTE RESULT")
    };

    UI._aiwkLoop = { getLoopEnabled: getLoopEnabled, getLoopMs: getLoopMs, setLoop: setLoop };
}());
