// 聊天消息渲染引擎：构建消息内容、追加消息、批量渲染与裁剪。
// 从 Blade 内联脚本 scripts.blade.php 迁移至 Vite 模块。

import { escapeHtml, normalizeSafeChatUrl } from "./html.js";
import { isExpiredChatImageMessage } from "./message-utils.js";
import { normalizeDailyStatus, resolveBlockedSystemSenderKey } from "./preferences-status.js";
import { escapePresenceText } from "./vip-presence.js";
import {
    BLOCKABLE_SYSTEM_SENDERS,
    PUBLIC_MESSAGE_NODE_LIMIT,
    PRIVATE_MESSAGE_NODE_LIMIT,
    CHAT_MESSAGE_FLUSH_BATCH_SIZE,
    SYSTEM_USERS,
    ACTION_TEXT_MAP,
} from "./chat-state.js";

// ── 游戏标签判断 ──
const GAME_LABEL_PREFIXES = ["五子棋", "双色球", "钓鱼", "老虎机", "百家乐", "赛马"];
function isGameLabel(name) {
    if (GAME_LABEL_PREFIXES.some((p) => name.startsWith(p))) return true;
    if (name.includes(" ")) return true;
    return false;
}

// ── 构建自然语序的动作串 ──
function buildActionStr(action, fromHtml, toHtml, verb = "说") {
    const info = ACTION_TEXT_MAP[action];
    if (!info) return `${fromHtml}对${toHtml}${escapeHtml(String(action || ""))}${verb}：`;
    if (info.type === "emotion") return `${fromHtml}${info.word}对${toHtml}${verb}：`;
    return `${fromHtml}${info.word}${toHtml}，${verb}：`;
}

// ── 可点击用户名 ──
function clickableUser(uName, color, extraClass = "") {
    const safeName = escapeHtml(uName);
    if (uName === "AI小班长") {
        return `<span class="msg-user${extraClass}" data-chat-message-user data-u="${safeName}" style="color: ${color}; cursor: pointer;">${safeName}</span>`;
    }
    if (SYSTEM_USERS.includes(uName) || isGameLabel(uName)) {
        return `<span class="msg-user${extraClass}" style="color: ${color};">${safeName}</span>`;
    }
    return `<span class="msg-user${extraClass}" data-chat-message-user data-u="${safeName}" style="color: ${color}; cursor: pointer;">${safeName}</span>`;
}

// ── 解析内容中【用户名】为可点击标记 ──
function parseBracketUsers(content, color = "#000099") {
    return content.replace(/【([^】]+)】/g, (_match, uName) => {
        return "【" + clickableUser(uName, color) + "】";
    });
}

/**
 * 构建聊天消息的内容 HTML。
 */
export function buildChatMessageContent(msg, fontColor, textColorClass) {
    const rawContent = msg.content || "";

    if (msg.message_type === "image" && !isExpiredChatImageMessage(msg)) {
        const fullUrl = escapeHtml(msg.image_url || "");
        const thumbUrl = escapeHtml(msg.image_thumb_url || "");
        const imageName = escapeHtml(msg.image_original_name || "聊天图片");
        const captionColorStyle = textColorClass ? "" : `color:${fontColor};`;
        const captionHtml = rawContent
            ? `<span class="msg-content${textColorClass || ""}" style="display:inline-block; max-width:220px; ${captionColorStyle} line-height:1.55;">${rawContent}</span>`
            : "";

        return `
            <span style="display:inline-flex; align-items:flex-start; gap:6px; vertical-align:middle;">
                <a href="${fullUrl}" data-full="${fullUrl}" data-alt="${imageName}" data-chat-image-lightbox-open
                    style="display:inline-block; border:1px solid rgba(15,23,42,.14); border-radius:10px; overflow:hidden; background:#f8fafc; box-shadow:0 2px 10px rgba(15,23,42,.10);">
                    <img src="${thumbUrl}" alt="${imageName}"
                        style="display:block; max-width:96px; max-height:96px; object-fit:cover; cursor:zoom-in;">
                </a>
                ${captionHtml}
            </span>
        `;
    }

    if (msg.message_type === "expired_image" || isExpiredChatImageMessage(msg)) {
        const captionColorStyle = textColorClass ? "" : `color:${fontColor};`;
        const captionHtml = rawContent
            ? `<span class="msg-content${textColorClass || ""}" style="display:inline-block; ${captionColorStyle} line-height:1.55;">${rawContent}</span>`
            : "";

        return `
            <span style="display:inline-flex; align-items:center; gap:6px; vertical-align:middle;">
                <span style="display:inline-flex; align-items:center; padding:4px 8px; border:1px dashed #94a3b8; border-radius:999px; background:#f8fafc; color:#64748b; font-size:12px;">🖼️ 图片已过期</span>
                ${captionHtml}
            </span>
        `;
    }

    return rawContent;
}

/**
 * 追加消息到聊天窗格（原版风格：非气泡模式，逐行显示）。
 *
 * @param {Object} msg 消息对象
 * @param {Object|null} renderBatch 批量渲染上下文
 */
export function appendMessage(msg, renderBatch = null) {
    const state = window.chatState;
    if (!state) return;

    state.trackMaxMsgId(msg.id || 0);

    const isMe = msg.from_user === window.chatContext?.username;
    const fontColor = msg.font_color || "#000000";
    const blockRuleKey = resolveBlockedSystemSenderKey(msg);
    const shouldHideByBlock = blockRuleKey ? state.blockedSystemSenders.has(blockRuleKey) : false;

    const div = document.createElement("div");
    div.className = "msg-line";
    if (msg?.from_user) {
        div.dataset.fromUser = msg.from_user;
    }
    if (blockRuleKey) {
        div.dataset.blockKey = blockRuleKey;
    }

    // ── 消息气泡装扮 ──
    if (msg.msg_bubble) {
        const bubbleStyle = msg.msg_bubble.replace(/^msg_bubble_/, "");
        div.classList.add("msg-bubble--" + bubbleStyle);
    }

    const timeStr = msg.sent_at || "";
    let timeStrOverride = false;

    let nameClass = "";
    if (msg.msg_name_color) {
        nameClass = " msg-name--" + msg.msg_name_color.replace(/^msg_name_/, "");
    }

    let textColorClass = "";
    if (msg.msg_text_color) {
        textColorClass = " msg-text--" + msg.msg_text_color.replace(/^msg_text_/, "");
    }

    // 用户头像
    const senderInfo = state.onlineUsers[msg.from_user];
    const senderHead = (senderInfo && senderInfo.headface) || "1.gif";
    let headImgSrc = senderHead.startsWith("storage/") ? "/" + senderHead : `/images/headface/${senderHead}`;
    if (msg.from_user.endsWith("播报") || msg.from_user === "星海小博士" || msg.from_user === "系统传音" || msg.from_user === "系统公告") {
        headImgSrc = "/images/bugle.png";
    }

    // ── 头像框装扮 ──
    let avatarFrameClass = null;
    const avatarFrameRaw = msg.avatar_frame || (senderInfo && senderInfo.avatar_frame);
    if (avatarFrameRaw) {
        avatarFrameClass = "avatar-frame--" + avatarFrameRaw.replace(/^avatar_frame_/, "");
    }

    let headImg = "";
    if (avatarFrameClass) {
        headImg = '<span class="avatar-frame-wrapper-sm">' +
            '<span class="avatar-frame ' + avatarFrameClass + '"></span>' +
            '<img src="' + headImgSrc + '" onerror="this.src=\'/images/headface/1.gif\'">' +
            '</span>';
    } else {
        headImg = '<img src="' + headImgSrc + '" style="display:inline;width:16px;height:16px;vertical-align:middle;margin-right:2px;mix-blend-mode: multiply;" onerror="this.src=\'/images/headface/1.gif\'">';
    }

    const messageBodyHtml = buildChatMessageContent(msg, fontColor, textColorClass);
    let html = "";

    // ── 消息路由 ──
    if (msg.action === "system_welcome") {
        div.style.cssText = "margin: 3px 0;";
        const iconImg = `<img src="/images/bugle.png" style="display:inline;width:16px;height:16px;vertical-align:middle;margin-right:2px;mix-blend-mode: multiply;" onerror="this.src='/images/headface/1.gif'">`;
        const parsedContent = parseBracketUsers(msg.content);
        html = `${iconImg} ${parsedContent}`;
    } else if (msg.action === "vip_presence") {
        const accent = msg.presence_color || "#f59e0b";
        div.style.cssText =
            `background: linear-gradient(135deg, #ffffff, ${accent}08); border: 2px solid ${accent}44; border-radius: 16px; padding: 12px 16px; margin: 8px 0; box-shadow: 0 4px 15px ${accent}15; position: relative; overflow: hidden;`;

        const icon = escapeHtml(msg.presence_icon || "👑");
        const levelName = escapeHtml(msg.presence_level_name || "尊贵会员");
        const typeLabel = msg.presence_type === "leave"
            ? "华丽离场"
            : (msg.presence_type === "purchase" ? "荣耀开通" : "荣耀入场");
        const safeText = escapePresenceText(msg.presence_text || "");

        html = `
            <div style="display:flex;align-items:center;gap:12px;">
                <div style="width:48px;height:48px;border-radius:14px;background:linear-gradient(135deg, ${accent}, #fbbf24);display:flex;align-items:center;justify-content:center;font-size:24px;box-shadow: 0 4px 12px ${accent}44; flex-shrink: 0;">${icon}</div>
                <div style="min-width:0;flex:1;">
                    <div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;">
                        <span style="font-size:13px;font-weight:900;letter-spacing:.05em;color:${accent}; text-shadow: 0.5px 0.5px 0px rgba(0,0,0,0.05);">${typeLabel}</span>
                        <span style="font-size:13px;color:#475569;font-weight:bold;">${levelName}</span>
                        <span style="font-size:11px;color:#94a3b8;">(${timeStr})</span>
                    </div>
                    <div style="margin-top:4px;font-size:15px;line-height:1.6;color:#1e293b;font-weight:500;">${safeText}</div>
                </div>
                <div style="position:absolute; right:-10px; bottom:-10px; font-size:60px; opacity:0.05; transform:rotate(-15deg); pointer-events:none;">${icon}</div>
            </div>
        `;
        timeStrOverride = true;
    } else if (msg.action === "欢迎") {
        div.style.cssText =
            "background: linear-gradient(135deg, #eff6ff, #f0f9ff); border: 1.5px solid #3b82f6; border-radius: 5px; padding: 5px 10px; margin: 3px 0; box-shadow: 0 1px 3px rgba(59,130,246,0.12);";
        const parsedContent = parseBracketUsers(msg.content, "#1d4ed8");
        html = `<div style="color: #1e40af;">💬 ${parsedContent} <span style="color: #93c5fd; font-size: 11px; font-weight: normal;">(${timeStr})</span></div>`;
        timeStrOverride = true;
    } else if (SYSTEM_USERS.includes(msg.from_user)) {
        if (msg.from_user === "系统公告") {
            div.style.cssText =
                "background: linear-gradient(135deg, #fef2f2, #fff1f2); border: 2px solid #ef4444; border-radius: 8px; padding: 10px 14px; margin: 6px 0; box-shadow: 0 3px 8px rgba(239,68,68,0.16);";
            const parsedContent = parseBracketUsers(msg.content, "#dc2626");
            html = `<div style="font-size: 18px; line-height: 1.75; font-weight: 800; color: #dc2626;">${parsedContent} <span style="color: #999; font-size: 14px; font-weight: 500;">(${timeStr})</span></div>`;
            timeStrOverride = true;
        } else if (msg.from_user === "系统传音") {
            const content = msg.content || "";
            const isRedPacketClaimNotification = content.includes("抢到了") && content.includes("礼包");
            const isBaccaratLossCoverNotification = content.includes("【你玩游戏我买单】") || content.includes("金币补偿");
            const isDailySignInNotification = content.includes("完成今日签到") || content.includes("使用补签卡补签");
            const isPlainNotification =
                content.includes("【百家乐】") ||
                content.includes("【赛马】") ||
                content.includes("神秘箱子") ||
                content.includes("【双色球") ||
                content.includes("【五子棋】") ||
                content.includes("【老虎机】") ||
                content.includes("购买了");

            if (isRedPacketClaimNotification || isBaccaratLossCoverNotification || isDailySignInNotification) {
                let plainAccentContent = parseBracketUsers(msg.content);
                html = `<span style="color: #b45309;">🌟 ${plainAccentContent}</span>`;
            } else if (isPlainNotification) {
                let parsedContent = parseBracketUsers(msg.content);
                html = `${headImg}<span style="font-weight: bold;">${clickableUser(msg.from_user, fontColor, nameClass)}：</span><span class="msg-content${textColorClass}" style="color: ${fontColor}; font-weight: bold;">${parsedContent}</span>`;
            } else {
                div.style.cssText =
                    "background: #fffbeb; border-left: 3px solid #d97706; border-radius: 4px; padding: 4px 10px; margin: 2px 0;";
                let sysTranContent = parseBracketUsers(msg.content);
                html = `<span style="color: #b45309;">🌟 ${sysTranContent}</span>`;
            }
        } else if (msg.from_user === "系统" && msg.to_user && msg.to_user !== "大家") {
            div.style.cssText =
                "background:#f0fdf4;border-left:3px solid #16a34a;border-radius:4px;padding:3px 8px;margin:2px 0;";
            html = `<span style="color:#16a34a;font-weight:bold;">📢 系统：</span><span style="color:#15803d;">${msg.content}</span>`;
        } else {
            let giftHtml = "";
            if (msg.gift_image) {
                giftHtml = `<img src="${msg.gift_image}" alt="${msg.gift_name || ""}" style="display:inline-block;width:40px;height:40px;vertical-align:middle;margin-left:6px;animation:giftBounce 0.6s ease-in-out;">`;
            }
            let parsedContent = parseBracketUsers(msg.content);
            html = `${headImg}<span style="font-weight: bold;">${clickableUser(msg.from_user, fontColor, nameClass)}：</span><span class="msg-content${textColorClass}" style="color: ${fontColor}">${parsedContent}</span>${giftHtml}`;
        }
    } else if (msg.is_secret) {
        if (msg.from_user === "系统") {
            div.style.cssText =
                "background:#f0fdf4;border-left:3px solid #16a34a;border-radius:4px;padding:3px 8px;margin:2px 0;font-size:12px;";
            html = `<span style="color:#16a34a;font-weight:bold;">📢 系统：</span><span style="color:#15803d;">${msg.content}</span>`;
        } else {
            const fromHtml = clickableUser(msg.from_user, "#cc00cc", nameClass);
            const toHtml = clickableUser(msg.to_user, "#cc00cc");
            const verbStr = msg.action ?
                buildActionStr(msg.action, fromHtml, toHtml, "悄悄说") :
                `${fromHtml}对${toHtml}悄悄说：`;
            html = `${headImg}<span class="msg-secret">${verbStr}</span><span class="msg-content${textColorClass}" style="color: ${fontColor}; font-style: italic;">${messageBodyHtml}</span>`;
        }
    } else if (msg.to_user && msg.to_user !== "大家") {
        const fromHtml = clickableUser(msg.from_user, "#000099", nameClass);
        const toHtml = clickableUser(msg.to_user, "#000099");
        const verbStr = msg.action ?
            buildActionStr(msg.action, fromHtml, toHtml) :
            `${fromHtml}对${toHtml}说：`;
        html = `${headImg}${verbStr}<span class="msg-content${textColorClass}" style="color: ${fontColor}">${messageBodyHtml}</span>`;
    } else {
        const fromHtml = clickableUser(msg.from_user, "#000099", nameClass);
        const everyoneHtml = clickableUser("大家", "#000099");
        const verbStr = msg.action ?
            buildActionStr(msg.action, fromHtml, everyoneHtml) :
            `${fromHtml}对${everyoneHtml}说：`;
        html = `${headImg}${verbStr}<span class="msg-content${textColorClass}" style="color: ${fontColor}">${messageBodyHtml}</span>`;
    }

    if (!timeStrOverride) {
        html += ` <span class="msg-time">(${timeStr})</span>`;
    }
    div.innerHTML = html;

    // 命中屏蔽规则时，消息仍保留在 DOM 中，便于取消屏蔽后立即恢复显示。
    if (shouldHideByBlock) {
        div.dataset.blockHidden = "1";
        div.style.display = "none";
    }

    // 后端下发的带有 welcome_user 的系统欢迎/离开消息，替换同类旧消息
    if (msg.welcome_user) {
        const welcomeKind = msg.welcome_kind || "entry_broadcast";
        div.setAttribute("data-system-user", msg.welcome_user);
        div.setAttribute("data-system-welcome-kind", welcomeKind);
        const removeSameWelcome = (root) => {
            root?.querySelectorAll("[data-system-user]").forEach((el) => {
                if (el.dataset.systemUser === msg.welcome_user && (el.dataset.systemWelcomeKind || "entry_broadcast") === welcomeKind) {
                    el.remove();
                }
            });
        };
        removeSameWelcome(state.container);
        removeSameWelcome(renderBatch?.publicFragment);
        removeSameWelcome(renderBatch?.privateFragment);
    }

    // 路由规则：公众窗口(say1) — 别人的公聊消息；包厢窗口(say2) — 自己发的 + 悄悄话 + 对自己说的
    const isRelatedToMe = isMe || msg.is_secret || msg.to_user === window.chatContext?.username;

    // 存点通知标记
    const isAutoSave = (msg.from_user === "系统" || msg.from_user === "") &&
        msg.content && (msg.content.includes("自动存点") || msg.content.includes("手动存点"));
    if (isAutoSave) {
        div.dataset.autosave = "1";
    }

    if (isRelatedToMe) {
        if (isAutoSave) {
            state.lastAutosaveNode?.remove();
            state.lastAutosaveNode = div;
        }
        if (renderBatch) {
            renderBatch.privateFragment.appendChild(div);
            renderBatch.shouldPrunePrivate = true;
            renderBatch.shouldScrollPrivate = renderBatch.shouldScrollPrivate || state.autoScroll;
            return;
        }
        const container2 = state.container2;
        if (container2) {
            container2.appendChild(div);
            pruneMessageContainer(container2, PRIVATE_MESSAGE_NODE_LIMIT);
            if (state.autoScroll) {
                container2.scrollTop = container2.scrollHeight;
            }
        }
    } else {
        if (renderBatch) {
            renderBatch.publicFragment.appendChild(div);
            renderBatch.shouldPrunePublic = true;
            renderBatch.shouldScrollPublic = renderBatch.shouldScrollPublic || state.autoScroll;
            return;
        }
        const container = state.container;
        if (container) {
            container.appendChild(div);
            pruneMessageContainer(container, PUBLIC_MESSAGE_NODE_LIMIT);
            if (state.autoScroll) {
                container.scrollTop = container.scrollHeight;
            }
        }
    }
}

/**
 * 裁剪聊天窗口内过旧的消息节点，防止长时间在线后 DOM 无限膨胀。
 */
export function pruneMessageContainer(targetContainer, maxNodes) {
    if (!targetContainer || targetContainer.childElementCount <= maxNodes) {
        return;
    }

    const state = window.chatState;
    while (targetContainer.childElementCount > maxNodes) {
        const firstNode = targetContainer.firstElementChild;
        if (state && firstNode === state.lastAutosaveNode) {
            state.lastAutosaveNode = null;
        }
        firstNode?.remove();
    }
}

/**
 * 创建聊天消息批量渲染上下文。
 */
export function createChatMessageRenderBatch() {
    return {
        publicFragment: document.createDocumentFragment(),
        privateFragment: document.createDocumentFragment(),
        shouldPrunePublic: false,
        shouldPrunePrivate: false,
        shouldScrollPublic: false,
        shouldScrollPrivate: false,
    };
}

/**
 * 提交批量渲染的聊天消息，并把裁剪和滚动合并到每批一次。
 */
export function commitChatMessageRenderBatch(renderBatch) {
    const state = window.chatState;
    if (!state) return;

    const hasPublicMessages = renderBatch.publicFragment.childNodes.length > 0;
    const hasPrivateMessages = renderBatch.privateFragment.childNodes.length > 0;

    if (hasPublicMessages) {
        const container = state.container;
        if (container) container.appendChild(renderBatch.publicFragment);
    }
    if (hasPrivateMessages) {
        const container2 = state.container2;
        if (container2) container2.appendChild(renderBatch.privateFragment);
    }
    if (renderBatch.shouldPrunePublic) {
        const container = state.container;
        if (container) pruneMessageContainer(container, PUBLIC_MESSAGE_NODE_LIMIT);
    }
    if (renderBatch.shouldPrunePrivate) {
        const container2 = state.container2;
        if (container2) pruneMessageContainer(container2, PRIVATE_MESSAGE_NODE_LIMIT);
    }
    if (renderBatch.shouldScrollPublic) {
        const container = state.container;
        if (container) container.scrollTop = container.scrollHeight;
    }
    if (renderBatch.shouldScrollPrivate) {
        const container2 = state.container2;
        if (container2) container2.scrollTop = container2.scrollHeight;
    }
}

/**
 * 将广播消息放入轻量队列，避免连续广播时同步挤占同一帧的 DOM 渲染。
 */
export function enqueueChatMessage(msg) {
    const state = window.chatState;
    if (!state) return;

    state.trackMaxMsgId(msg.id || 0);
    state.pendingChatMessages.push(msg);

    if (state.chatMessageFlushTimer !== null) {
        return;
    }

    const scheduleFlush = window.requestAnimationFrame || ((callback) => window.setTimeout(callback, 16));
    state.chatMessageFlushTimer = scheduleFlush(flushQueuedChatMessages);
}

/**
 * 分批渲染待处理消息，给动画、输入和滚动留出主线程时间。
 */
export function flushQueuedChatMessages() {
    const state = window.chatState;
    if (!state) return;

    state.chatMessageFlushTimer = null;

    const batch = state.pendingChatMessages.splice(0, CHAT_MESSAGE_FLUSH_BATCH_SIZE);
    const renderBatch = createChatMessageRenderBatch();
    batch.forEach((msg) => appendMessage(msg, renderBatch));
    commitChatMessageRenderBatch(renderBatch);

    if (state.pendingChatMessages.length === 0) {
        return;
    }

    const scheduleFlush = window.requestAnimationFrame || ((callback) => window.setTimeout(callback, 16));
    state.chatMessageFlushTimer = scheduleFlush(flushQueuedChatMessages);
}

// ── 挂载到 window 供 Blade 脚本及其他模块使用 ──
window.appendMessage = appendMessage;
window.buildChatMessageContent = buildChatMessageContent;
window.pruneMessageContainer = pruneMessageContainer;
window.createChatMessageRenderBatch = createChatMessageRenderBatch;
window.commitChatMessageRenderBatch = commitChatMessageRenderBatch;
window.enqueueChatMessage = enqueueChatMessage;
window.flushQueuedChatMessages = flushQueuedChatMessages;

export { clickableUser, buildActionStr, parseBracketUsers };
