1jQuery(function() {
2    if (document.getElementById("xmppsupport-chat-trigger")) return;
3
4    const path = (typeof DOKU_BASE !== 'undefined' ? DOKU_BASE : '/') + "lib/plugins/xmppsupport/";
5    let conn = null, nick = "anon-client", op = "";
6
7    const box = document.createElement("div"); box.id = "xmppsupport-chat-box";
8    const header = document.createElement("div"); header.id = "xmppsupport-chat-header";
9    const title = document.createElement("span"); title.id = "xmppsupport-header-title"; title.textContent = "Live Support Chat";
10    const status = document.createElement("span"); status.id = "xmppsupport-header-status"; status.textContent = " (connecting...)";
11    Object.assign(status.style, { fontSize: "11px", opacity: "0.8", marginLeft: "5px" });
12    header.append(title, status);
13
14    const area = document.createElement("div"); area.id = "xmppsupport-chat-messages";
15    const footer = document.createElement("div"); footer.id = "xmppsupport-chat-footer";
16    const input = document.createElement("input"); Object.assign(input, { type: "text", id: "xmppsupport-chat-input", placeholder: "Type a message...", autocomplete: "off" });
17    footer.appendChild(input); box.append(header, area, footer); document.body.appendChild(box);
18
19    function append(txt, type, save = true) {
20        const msg = document.createElement("div"); msg.className = `xmpp-msg ${type}`; msg.textContent = txt;
21        area.appendChild(msg); area.scrollTop = area.scrollHeight;
22        if (save) {
23            try {
24                let h = JSON.parse(localStorage.getItem("xmpp_chat_history")) || [];
25                h.push({ text: txt, type: type });
26                localStorage.setItem("xmpp_chat_history", JSON.stringify(h));
27            } catch(e) {}
28        }
29    }
30
31    try {
32        (JSON.parse(localStorage.getItem("xmpp_chat_history")) || []).forEach(i => append(i.text, i.type, false));
33    } catch(e) {}
34
35    let cookies = `; ${document.cookie}`.split(`; xmpp_support_nick=`);
36    if (cookies.length === 2) nick = cookies.pop().split(';').shift();
37    else {
38        const adjs = ["Swift", "Bright", "Clever", "Calm", "Bold", "Sly", "Wild", "Noble", "Eager", "Vast", "Iron", "Shadow", "Frost", "Flaring", "Silent"];
39        const nns = ["Falcon", "Wizard", "Phoenix", "Wolf", "Knight", "Fox", "Raven", "Gargoyle", "Forge", "Golem", "Warden", "Specter", "Drake", "Sentinel", "Citadel"];
40        nick = `${adjs[Math.floor(Math.random() * adjs.length)]}-${nns[Math.floor(Math.random() * nns.length)]}`.toLowerCase();
41        let d = new Date(); d.setTime(d.getTime() + (365 * 24 * 3600 * 1000));
42        document.cookie = `xmpp_support_nick=${nick}; expires=${d.toUTCString()}; path=/; SameSite=Lax`;
43    }
44
45    const scr = document.createElement("script"); scr.src = path + "strophe.min.js"; scr.charset = "utf-8";
46    scr.onload = function() {
47        if (typeof Strophe === 'undefined') return;
48
49        function onMsg(st) {
50            const b = st.getElementsByTagName('body');
51            if (b.length > 0 && (st.getAttribute('from') || '').toLowerCase().includes(op.toLowerCase())) append(Strophe.getText(b[0]), 'incoming');
52            return true;
53        }
54
55        function onPres(st) {
56            if (!(st.getAttribute('from') || '').toLowerCase().includes(op.toLowerCase())) return true;
57            if (st.getAttribute('type') === 'unavailable') { status.textContent = " (offline)"; return true; }
58            const s = st.getElementsByTagName('show'), t = st.getElementsByTagName('status');
59            const map = { away: " (away)", chat: " (free for chat)", dnd: " (do not disturb)", xa: " (extended away)", online: " (online)" };
60            status.textContent = t.length > 0 ? ` (${Strophe.getText(t[0])})` : (map[s.length > 0 ? Strophe.getText(s[0]) : 'online'] || " (online)");
61            return true;
62        }
63
64        function loop(st) {
65            if (st === Strophe.Status.CONNECTED) {
66                status.textContent = " (online)";
67                conn.addHandler(onMsg, null, 'message', 'chat');
68                conn.addHandler(onPres, null, 'presence');
69                conn.send($pres().tree()); conn.send($pres({ to: op, type: 'subscribe' }).tree());
70            } else if (st === Strophe.Status.DISCONNECTED) {
71                status.textContent = " (connecting...)"; setTimeout(() => connect(), 4000);
72            }
73        }
74
75        let cachedConfig = null;
76        function connect(cfg) {
77            if (cfg) cachedConfig = cfg;
78            if (!cachedConfig) return;
79
80            conn = new Strophe.Connection(cachedConfig.websocket);
81            op = cachedConfig.operator;
82
83            const targetDomain = cachedConfig.domain;
84            const jid = `${nick}@${targetDomain}`;
85
86            conn.connect(jid, nick, function(st) {
87                if (st === Strophe.Status.AUTHFAIL) {
88                    const reg = $iq({ type: "set", to: targetDomain, id: "reg-1" })
89                        .c("query", { xmlns: "jabber:iq:register" }).c("username").t(nick).up().c("password").t(nick);
90                    conn.sendIQ(reg, () => conn.connect(jid, nick, loop), (err) => {
91                        const cond = err.getElementsByTagName("conflict");
92                        if (cond.length > 0) conn.connect(jid, nick, loop);
93                    });
94                } else loop(st);
95            });
96        }
97
98        fetch(path + "config.php").then(r => r.json()).then(d => {
99            if (d?.title) title.textContent = d.title;
100            connect(d);
101        }).catch(() => {});
102    };
103    document.head.appendChild(scr);
104
105    const trig = document.createElement("div"); trig.id = "xmppsupport-chat-trigger";
106    Object.assign(trig.style, { position: "fixed", bottom: "20px", right: "20px", width: "44px", height: "44px", backgroundColor: "#fff", boxShadow: "0 3px 10px rgba(0,0,0,0.22)", cursor: "pointer", zIndex: "2147483647", display: "flex", alignItems: "center", justifyContent: "center", border: "1px solid #ccc" });
107    const img = document.createElement("img"); Object.assign(img.style, { width: "24px", height: "24px", display: "block" }); img.src = path + "images/gate.png";
108    trig.appendChild(img); document.body.appendChild(trig);
109
110    // FIX: Updated click target name handler hook properties to match trig explicitly
111    trig.addEventListener("click", () => {
112        box.style.display = window.getComputedStyle(box).display === 'none' ? 'flex' : 'none';
113        if (box.style.display === 'flex') input.focus();
114    });
115
116    input.addEventListener("keydown", (e) => {
117        if (e.key === "Enter" && input.value.trim() !== "") {
118            const txt = input.value.trim();
119            if (conn?.connected) {
120                conn.send($msg({ to: op, type: 'chat' }).c('body').t(txt).tree());
121                append(txt, 'outgoing'); input.value = "";
122            } else append("Connecting to support server...", "incoming", false);
123        }
124    });
125});
126