// 聊天室 WebSocket 事件监听，从 Blade 内联脚本 scripts.blade.php 迁移至 Vite 模块。
// 所有事件委托通过 window.addEventListener 注册，依赖 window.chatState 共享状态。

import { escapeHtml, normalizeSafeChatUrl } from "./html.js";
import { normalizeDailyStatus } from "./preferences-status.js";
import { enqueueChatMessage } from "./message-renderer.js";
import { isAutoScrollEnabled, scrollChatToBottom } from "./message-utils.js";

// ── 事件注册标记 ──
let chatEventsBound = false;
let chatWebSocketInitRetryTimer = null;
const GOMOKU_INVITE_BUTTON_FONT_SIZE = "0.82em";

// ── 辅助函数 ──
function csrf() {
    return document.querySelector('meta[name="csrf-token"]')?.content ?? "";
}

function getState() {
    return window.chatState;
}

/**
 * 在开启自动滚屏时把指定聊天窗格滚动到底部。
 *
 * @param {HTMLElement|null|undefined} container 聊天消息容器
 * @returns {void}
 */
function scrollWhenEnabled(container) {
    scrollChatToBottom(container, isAutoScrollEnabled);
}

/**
 * 启动 WebSocket 初始化（DOMContentLoaded 之后调用）。
 */
function initChatWebSocket() {
    if (chatWebSocketInitRetryTimer) {
        window.clearTimeout(chatWebSocketInitRetryTimer);
        chatWebSocketInitRetryTimer = null;
    }

    if (typeof window.initChat === "function" && window.chatContext?.roomId) {
        window.initChat(window.chatContext.roomId);
        return;
    }

    // chat.js 会在模块末尾才把 initChat 挂到 window；若这里抢先执行，稍后自动补一次初始化。
    chatWebSocketInitRetryTimer = window.setTimeout(() => {
        chatWebSocketInitRetryTimer = null;
        initChatWebSocket();
    }, 100);
}

/**
 * 在 DOM 已就绪时立即执行回调，避免 Vite 模块晚于 DOMContentLoaded 执行时漏掉初始化。
 *
 * @param {() => void} callback 页面就绪后的回调
 * @returns {void}
 */
function runWhenDomReady(callback) {
    if (typeof callback !== "function") {
        return;
    }

    if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", callback, { once: true });
        return;
    }

    callback();
}

/**
 * 判断 Toast 通知是否需要对当前用户隐藏。
 *
 * @param {Record<string, any>} toastNotification 右下角通知载荷
 * @returns {boolean}
 */
function shouldSkipToastForCurrentUser(toastNotification) {
    if (!toastNotification?.skip_for_actor) {
        return false;
    }

    return String(toastNotification.actor_username || "") === String(window.chatContext?.username || "");
}

// ── 禁言逻辑 ──
function handleMutedEvent(e) {
    const state = getState();
    const d = e.detail;
    const now = new Date();
    const timeStr = now.getHours().toString().padStart(2, "0") + ":" +
        now.getMinutes().toString().padStart(2, "0") + ":" +
        now.getSeconds().toString().padStart(2, "0");

    const isMe = d.username === window.chatContext?.username;

    const div = document.createElement("div");
    div.className = "msg-line";
    div.innerHTML = `<span style="color: #c00; font-weight: bold;">【系统】${d.message}</span><span class="msg-time">(${timeStr})</span>`;

    const targetContainer = isMe
        ? document.getElementById("say2")
        : (state?.container);
    if (targetContainer) {
        targetContainer.appendChild(div);
        scrollWhenEnabled(targetContainer);
    }

    if (isMe && d.mute_time > 0) {
        state.isMutedUntil = Date.now() + d.mute_time * 60 * 1000;
        const contentInput = document.getElementById("content");
        const operatorName = d.operator || "管理员";
        if (contentInput) {
            contentInput.placeholder = `${operatorName} 已将您禁言 ${d.mute_time} 分钟，解禁后方可发言...`;
            contentInput.disabled = true;
            setTimeout(() => {
                state.isMutedUntil = 0;
                contentInput.placeholder = "在这里输入聊天内容，按 Enter 发送...";
                contentInput.disabled = false;
                const unmuteDiv = document.createElement("div");
                unmuteDiv.className = "msg-line";
                unmuteDiv.innerHTML = '<span style="color: #16a34a; font-weight: bold;">【系统】您的禁言已解除，可以继续发言了。</span>';
                const say2 = document.getElementById("say2");
                if (say2) {
                    say2.appendChild(unmuteDiv);
                    scrollWhenEnabled(say2);
                }
            }, d.mute_time * 60 * 1000);
        }
    }
}

// ── Echo 级监听器 ──

/**
 * 注册全员清屏监听（ScreenCleared）。
 */
function setupScreenClearedListener() {
    if (!window.Echo || !window.chatContext) {
        setTimeout(setupScreenClearedListener, 500);
        return;
    }
    window.Echo.join(`room.${window.chatContext.roomId}`)
        .listen("ScreenCleared", (e) => {
            const operator = e.operator;
            const safeOperator = escapeHtml(String(operator || ""));

            const say1 = document.getElementById("chat-messages-container");
            if (say1) say1.innerHTML = "";

            const say2 = document.getElementById("chat-messages-container2");
            if (say2) {
                const items = say2.querySelectorAll(".msg-line");
                items.forEach((item) => {
                    if (!item.querySelector(".msg-secret")) {
                        item.remove();
                    }
                });
            }

            const state = getState();
            if (state) {
                state.lastAutosaveNode = say2?.querySelector('[data-autosave="1"]') || null;
            }

            const sysDiv = document.createElement("div");
            sysDiv.className = "msg-line";
            const now = new Date();
            const timeStr = now.getHours().toString().padStart(2, "0") + ":" +
                now.getMinutes().toString().padStart(2, "0") + ":" +
                now.getSeconds().toString().padStart(2, "0");
            sysDiv.innerHTML = `<span style="color: #dc2626; font-weight: bold;">🧹 管理员 <b>${safeOperator}</b> 已执行全员清屏</span><span class="msg-time">(${timeStr})</span>`;
            if (say1) {
                say1.appendChild(sysDiv);
                scrollWhenEnabled(say1);
            }
        });
}

/**
 * 注册房间级"刷新全员"监听（BrowserRefreshRequested）。
 */
function setupRoomBrowserRefreshListener() {
    if (!window.Echo || !window.chatContext) {
        setTimeout(setupRoomBrowserRefreshListener, 500);
        return;
    }
    window.Echo.join(`room.${window.chatContext.roomId}`)
        .listen("BrowserRefreshRequested", (e) => {
            window.dispatchEvent(
                new CustomEvent("chat:browser-refresh-requested", { detail: e })
            );
        });
}

/**
 * 注册开发日志发布通知监听（仅 Room 1）。
 */
function setupChangelogPublishedListener() {
    if (!window.Echo || !window.chatContext) {
        setTimeout(setupChangelogPublishedListener, 500);
        return;
    }
    if (window.chatContext.roomId !== 1) return;

    window.Echo.join("room.1")
        .listen(".ChangelogPublished", (e) => {
            const now = new Date();
            const timeStr = now.getHours().toString().padStart(2, "0") + ":" +
                now.getMinutes().toString().padStart(2, "0") + ":" +
                now.getSeconds().toString().padStart(2, "0");
            const safeVersion = e.safe_version ?? escapeHtml(String(e.version ?? ""));
            const safeTitle = e.safe_title ?? escapeHtml(String(e.title ?? ""));
            const changelogRoute = window.chatContext?.changelogUrl || "/changelog";
            const safeUrl = escapeHtml(normalizeSafeChatUrl(e.url, changelogRoute));

            const sysDiv = document.createElement("div");
            sysDiv.className = "msg-line";
            sysDiv.style.cssText =
                "background: #fffbeb; border-left: 3px solid #d97706; border-radius: 4px; padding: 5px 10px; margin: 3px 0;";
            sysDiv.innerHTML = `<span style="color: #b45309; font-weight: bold;">
                📋 【版本更新】v${safeVersion} · ${safeTitle}
                <a href="${safeUrl}" target="_blank" rel="noopener"
                    style="color: #7c3aed; text-decoration: underline; margin-left: 8px; font-size: 0.85em;">
                    查看详情 →
                </a>
            </span><span class="msg-time">(${timeStr})</span>`;

            const say1 = document.getElementById("chat-messages-container");
            if (say1) {
                say1.appendChild(sysDiv);
                scrollWhenEnabled(say1);
            }
        });
}

/**
 * 注册五子棋 PvP 邀请通知监听。
 */
function setupGomokuInviteListener() {
    if (!window.Echo || !window.chatContext) {
        setTimeout(setupGomokuInviteListener, 500);
        return;
    }
    window.Echo.join(`room.${window.chatContext.roomId}`)
        .listen(".gomoku.invite", (e) => {
            const now = new Date();
            const timeStr = now.getHours().toString().padStart(2, "0") + ":" +
                now.getMinutes().toString().padStart(2, "0") + ":" +
                now.getSeconds().toString().padStart(2, "0");

            const isSelf = (e.inviter_name === window.chatContext.username);
            const div = document.createElement("div");
            div.className = "msg-line";
            div.style.cssText =
                "background:linear-gradient(135deg,#e8eef8,#f0f4fc); border-left:3px solid #336699; border-radius:4px; padding:6px 10px; margin:3px 0;";
            const safeInviterName = escapeHtml(e.inviter_name);
            const gomokuGameId = Number.parseInt(e.game_id, 10) || 0;

            const acceptBtn = isSelf
                ? `<button type="button" data-gomoku-open-panel class="gomoku-invite-open"
                   style="margin-left:10px; padding:3px 12px; border:1.5px solid #2d6096;
                          border-radius:12px; background:#f0f6ff; color:#2d6096; font-size:${GOMOKU_INVITE_BUTTON_FONT_SIZE};
                          cursor:pointer; font-family:inherit; transition:all .15s;">
                   ⤴️ 打开面板
               </button>`
                : `<button type="button" data-gomoku-accept-id="${gomokuGameId}" id="gomoku-accept-${gomokuGameId}" class="gomoku-invite-accept"
                   style="margin-left:10px; padding:3px 12px; border:1.5px solid #336699;
                          border-radius:12px; background:#336699; color:#fff; font-size:${GOMOKU_INVITE_BUTTON_FONT_SIZE};
                          cursor:pointer; font-family:inherit; transition:opacity .15s;">
                   ⚔️ 接受挑战
               </button>`;

            div.innerHTML = `<span style="color:#1e3a5f; font-weight:bold;">
                ♟️ 【五子棋】<b>${safeInviterName}</b> 发起了随机对战！${isSelf ? "（等待中）" : ""}
            </span>${acceptBtn}
            <span class="msg-time">(${timeStr})</span>`;

            const say1 = document.getElementById("chat-messages-container");
            if (say1) {
                say1.appendChild(div);
                scrollWhenEnabled(say1);
            }

            if (!isSelf) {
                setTimeout(() => {
                    const btn = document.getElementById(`gomoku-accept-${e.game_id}`);
                    if (btn) {
                        btn.textContent = "已超时";
                        btn.disabled = true;
                        btn.style.opacity = ".5";
                        btn.style.cursor = "not-allowed";
                    }
                }, 60000);
            }
        })
        .listen(".gomoku.finished", (e) => {
            if (e.mode !== "pvp") return;
            const now = new Date();
            const timeStr = now.getHours().toString().padStart(2, "0") + ":" +
                now.getMinutes().toString().padStart(2, "0") + ":" +
                now.getSeconds().toString().padStart(2, "0");

            const div = document.createElement("div");
            div.className = "msg-line";
            div.style.cssText =
                "background:#fffae8; border-left:3px solid #d97706; border-radius:4px; padding:5px 10px; margin:2px 0;";

            const reason = { win: "获胜", draw: "平局", resign: "认输", timeout: "超时" }[e.reason] || "结束";
            let text = "";
            if (e.winner === 0) {
                text = `♟️ 五子棋对局以<b>平局</b>结束！`;
            } else {
                text = `♟️ <b>${e.winner_name}</b> 击败 <b>${e.loser_name}</b>（${reason}）获得 <b style="color:#b45309;">${e.reward_gold}</b> 金币！`;
            }

            div.innerHTML = `<span style="color:#92400e;">${text}</span><span class="msg-time">(${timeStr})</span>`;
            const say1 = document.getElementById("chat-messages-container");
            if (say1) {
                say1.appendChild(div);
                scrollWhenEnabled(say1);
            }
        });
}

// ── 主事件绑定 ──

/**
 * 绑定所有聊天室 WebSocket 事件监听，仅执行一次。
 */
export function bindChatEvents() {
    if (chatEventsBound || typeof document === "undefined") {
        return;
    }
    chatEventsBound = true;

    // 页面已完成解析时立刻补做初始化，确保 Presence 连接不会因为错过 DOMContentLoaded 而丢失。
    runWhenDomReady(initChatWebSocket);

    // chat:here — Presence 初始用户列表
    window.addEventListener("chat:here", (e) => {
        const state = getState();
        if (!state) return;

        const users = e.detail;
        state.onlineUsers = {};
        users.forEach((u) => {
            window.hydrateOnlineUserPayload(u.username, u);
        });

        // 注入 AI 小班长
        if (window.chatContext?.chatBotEnabled && window.chatContext.botUser) {
            window.hydrateOnlineUserPayload("AI小班长", window.chatContext.botUser);
        }

        // 同步当前用户状态
        if (typeof window.setOnlineUserDailyStatus === "function" && typeof window.getCurrentUserDailyStatus === "function") {
            window.setOnlineUserDailyStatus(window.chatContext?.username, window.getCurrentUserDailyStatus());
        }
        if (typeof window.syncDailyStatusUi === "function") {
            window.syncDailyStatusUi();
        }
        window.scheduleRenderUserList(0);
    });

    // chat:bot-toggled — AI 小班长动态开关
    window.addEventListener("chat:bot-toggled", (e) => {
        const detail = e.detail;
        if (window.chatContext) {
            window.chatContext.chatBotEnabled = detail.isOnline;
        }

        if (detail.isOnline && detail.user && detail.user.username) {
            window.hydrateOnlineUserPayload(detail.user.username, detail.user);
            if (window.chatContext) window.chatContext.botUser = detail.user;
        } else {
            const state = getState();
            if (state) delete state.onlineUsers["AI小班长"];
            if (window.chatContext) window.chatContext.botUser = null;
        }
        window.scheduleRenderUserList?.();
    });

    // chat:user-status-updated — 用户每日状态更新
    window.addEventListener("chat:user-status-updated", (e) => {
        const username = e.detail?.username;
        const payload = e.detail?.user;
        if (!username || !payload) return;

        window.hydrateOnlineUserPayload(username, payload);

        if (username === window.chatContext?.username) {
            if (window.chatContext) {
                window.chatContext.currentDailyStatus = normalizeDailyStatus(payload);
            }
            if (typeof window.syncDailyStatusUi === "function") {
                window.syncDailyStatusUi();
            }
        }
        window.scheduleRenderUserList?.();
    });

    // chat:joining — 用户进入
    window.addEventListener("chat:joining", (e) => {
        const user = e.detail;
        window.hydrateOnlineUserPayload(user.username, user);
        window.scheduleRenderUserList?.();
    });

    // chat:leaving — 用户离开
    window.addEventListener("chat:leaving", (e) => {
        const user = e.detail;
        const state = getState();
        if (state) delete state.onlineUsers[user.username];
        window.scheduleRenderUserList?.();
    });

    // chat:message — 新消息
    window.addEventListener("chat:message", (e) => {
        const msg = e.detail;
        if (msg.is_secret && msg.from_user !== window.chatContext?.username && msg.to_user !== window.chatContext?.username) {
            return;
        }
        enqueueChatMessage(msg);

        if (msg.action === "vip_presence" && typeof window.showVipPresenceBanner === "function") {
            window.showVipPresenceBanner(msg);
        }

        // 若消息携带 toast_notification 字段且当前用户是接收者或为公屏广播或为欢迎动作，弹右下角小卡片
        if (msg.toast_notification && (msg.to_user === window.chatContext?.username || msg.to_user === '大家' || msg.action === '欢迎')) {
            const t = msg.toast_notification;
            if (shouldSkipToastForCurrentUser(t)) {
                return;
            }

            window.chatToast?.show({
                title: t.title || "通知",
                message: t.message || "",
                icon: t.icon || "💬",
                color: t.color || "#336699",
                duration: t.duration ?? 8000,
            });
        }
    });

    // chat:kicked — 被踢出房间
    window.addEventListener("chat:kicked", (e) => {
        if (e.detail.username === window.chatContext?.username) {
            const roomsIndexUrl = window.chatContext?.roomsIndexUrl || "/rooms";
            window.chatDialog?.alert(
                "您已被管理员踢出房间！" + (e.detail.reason ? " 原因：" + e.detail.reason : ""),
                "系统通知",
                "#cc4444"
            );
            window.location.href = roomsIndexUrl;
        }
    });

    // chat:muted — 禁言事件
    window.addEventListener("chat:muted", handleMutedEvent);

    // chat:title-updated — 房间标题更新
    window.addEventListener("chat:title-updated", (e) => {
        const display = document.getElementById("room-title-display");
        if (display) display.innerText = e.detail.title;
    });

    // chat:browser-refresh-requested — 全员刷新通知
    window.addEventListener("chat:browser-refresh-requested", (e) => {
        const detail = e.detail || {};
        const operatorName = escapeHtml(String(detail.operator || "站长"));
        const reasonText = escapeHtml(String(detail.reason || "页面功能已更新，请重新载入。"));

        window.chatToast?.show({
            title: "页面即将刷新",
            message: `<b>${operatorName}</b> 通知全员刷新页面。<br><span style="color:#475569;">${reasonText}</span>`,
            icon: "♻️",
            color: "#0f766e",
            duration: 2200,
        });

        window.setTimeout(() => {
            window.location.reload();
        }, 900);
    });

    // chat:user-browser-refresh-requested — 目标用户定向刷新
    window.addEventListener("chat:user-browser-refresh-requested", (e) => {
        const detail = e.detail || {};
        const operatorName = escapeHtml(String(detail.operator || "管理员"));
        const reasonText = escapeHtml(String(detail.reason || "你的权限状态已发生变化，页面即将刷新。"));

        window.chatToast?.show({
            title: "权限同步中",
            message: `<b>${operatorName}</b> 已更新你的职务状态。<br><span style="color:#475569;">${reasonText}</span>`,
            icon: "🔄",
            color: "#7c3aed",
            duration: 2600,
        });

        window.setTimeout(() => {
            window.location.reload();
        }, 1000);
    });

    // chat:effect — 全屏特效事件
    window.addEventListener("chat:effect", (e) => {
        const type = e.detail?.type;
        const target = e.detail?.target_username;
        const operator = e.detail?.operator;
        const myName = window.chatContext?.username;
        const effectOptions = {
            effect_title: e.detail?.effect_title,
            effect_user_info: e.detail?.effect_user_info,
            ride_name: e.detail?.ride_name,
            operator,
        };

        if (type && typeof EffectManager !== "undefined") {
            if (!target || target === myName || operator === myName) {
                EffectManager.play(type, effectOptions);
            }
        }
    });

    // chat:pat — 拍一拍事件
    window.addEventListener("chat:pat", (e) => {
        const { from_user, target_user, display_text, from_user_headface } = e.detail || {};
        if (!display_text) return;

        if (typeof window.appendPatMessage === "function") {
            window.appendPatMessage(display_text, from_user_headface, from_user, target_user);
        }
        if (typeof window.triggerPatShake === "function") {
            window.triggerPatShake();
        }
    });

    // chat:idiom-started — 猜成语出题
    window.addEventListener("chat:idiom-started", (e) => {
        if (typeof window.handleRiddleGameStarted === "function") {
            window.handleRiddleGameStarted(e);
        }
    });

    // chat:idiom-answered — 猜成语答题结果
    window.addEventListener("chat:idiom-answered", (e) => {
        if (typeof window.handleRiddleGameAnswered === "function") {
            window.handleRiddleGameAnswered(e);
        }
    });

    // Echo 级监听器同样要兼容“脚本加载时页面已完成”的场景。
    runWhenDomReady(() => {
        setupScreenClearedListener();
        setupRoomBrowserRefreshListener();
        setupChangelogPublishedListener();
        setupGomokuInviteListener();
    });
}

export { initChatWebSocket };
