/**
 * 主对话区智能粘底滚动：流式输出时自动跟随，用户上滑阅读时不抢焦点。
 * 主 POST 流（sendMessage）与刷新后 task-events 补流共用同一策略。
 */
(function () {
    'use strict';

    /** 距底部在此范围内才继续自动跟随（宜小，避免“差一点也被拽回去”） */
    const CHAT_SCROLL_FOLLOW_THRESHOLD_PX = 48;
    /** FAB 隐藏：用户已手动滚近底部 */
    const CHAT_SCROLL_FAB_HIDE_THRESHOLD_PX = 120;
    /** 用户上滑后的短暂锁，防止 SSE 与 scroll 事件竞态抢滚动 */
    const DETACH_LOCK_MS = 280;

    /** @type {'following' | 'detached'} */
    let scrollMode = 'following';
    let scrollFollowRaf = 0;
    /** 用户脱离跟随后，下方是否有未读的新输出（不按 SSE 次数计） */
    let hasPendingNewBelow = false;
    let listenersBound = false;
    let lastScrollTop = 0;
    let programmaticScroll = false;
    let detachLockUntil = 0;

    function getChatMessagesEl() {
        return document.getElementById('chat-messages');
    }

    /** 主 POST 流 + 刷新后 task-events 补流均视为「流式进行中」 */
    function isStreamActive() {
        try {
            const live = window.__csAgentLiveStream;
            if (live && live.active) return true;
            const replay = window.__csTaskEventStream;
            return !!(replay && replay.active);
        } catch (e) {
            return false;
        }
    }

    function distanceFromBottom(el) {
        if (!el) return 0;
        const { scrollTop, scrollHeight, clientHeight } = el;
        return scrollHeight - clientHeight - scrollTop;
    }

    function isNearBottom(thresholdPx) {
        const el = getChatMessagesEl();
        if (!el) return true;
        return distanceFromBottom(el) <= thresholdPx;
    }

    function isChatMessagesPinnedToBottom() {
        return isNearBottom(CHAT_SCROLL_FAB_HIDE_THRESHOLD_PX);
    }

    /** 已在底部时恢复 following（解决：手动滚到底但 scrollMode 仍为 detached） */
    function resumeFollowingIfAtBottom() {
        if (Date.now() < detachLockUntil) return false;
        if (!isNearBottom(CHAT_SCROLL_FOLLOW_THRESHOLD_PX)) return false;
        if (scrollMode === 'detached') setScrollFollowing();
        return true;
    }

    function captureScrollPinState() {
        if (Date.now() < detachLockUntil) return false;
        if (resumeFollowingIfAtBottom()) return true;
        return scrollMode === 'following';
    }

    function setScrollFollowing() {
        scrollMode = 'following';
        detachLockUntil = 0;
        hasPendingNewBelow = false;
        updateScrollToBottomFab();
    }

    function markPendingNewBelow() {
        if (scrollMode !== 'detached') return;
        hasPendingNewBelow = true;
        updateScrollToBottomFab();
    }

    function setScrollDetached() {
        scrollMode = 'detached';
        detachLockUntil = Date.now() + DETACH_LOCK_MS;
        cancelAnimationFrame(scrollFollowRaf);
        if (isStreamActive()) {
            hasPendingNewBelow = true;
        }
        updateScrollToBottomFab();
    }

    function scrollChatToBottomInstant() {
        if (scrollMode !== 'following') return;
        const el = getChatMessagesEl();
        if (!el) return;
        programmaticScroll = true;
        el.scrollTop = el.scrollHeight;
        lastScrollTop = el.scrollTop;
        requestAnimationFrame(function () {
            programmaticScroll = false;
        });
    }

    function scrollChatToBottomSmooth() {
        const el = getChatMessagesEl();
        if (!el) return;
        programmaticScroll = true;
        el.scrollTo({ top: el.scrollHeight, behavior: 'smooth' });
        requestAnimationFrame(function () {
            programmaticScroll = false;
            const node = getChatMessagesEl();
            if (node) lastScrollTop = node.scrollTop;
        });
    }

    function updateScrollToBottomFab() {
        const fab = document.getElementById('chat-scroll-to-bottom');
        if (!fab) return;

        const show = scrollMode === 'detached' && !isNearBottom(CHAT_SCROLL_FAB_HIDE_THRESHOLD_PX);
        fab.classList.toggle('visible', show);

        let label;
        if (hasPendingNewBelow) {
            label = typeof window.t === 'function'
                ? window.t('chat.scrollToBottomHasNew')
                : '↓ 有新内容';
        } else {
            label = typeof window.t === 'function'
                ? window.t('chat.scrollToBottom')
                : '回到底部';
        }
        fab.setAttribute('aria-label', label);
        fab.textContent = label;
    }

    function canAutoScrollNow(wasPinnedBeforeDomUpdate) {
        if (Date.now() < detachLockUntil) return false;
        if (resumeFollowingIfAtBottom()) return true;
        if (scrollMode === 'detached') return false;
        if (wasPinnedBeforeDomUpdate === true) return true;
        return isNearBottom(CHAT_SCROLL_FOLLOW_THRESHOLD_PX);
    }

    function scheduleChatScrollToBottomIfFollowing(wasPinnedBeforeDomUpdate) {
        if (!canAutoScrollNow(wasPinnedBeforeDomUpdate)) {
            markPendingNewBelow();
            return;
        }
        cancelAnimationFrame(scrollFollowRaf);
        scrollFollowRaf = requestAnimationFrame(scrollChatToBottomInstant);
    }

    /** @param {boolean} wasPinned DOM 更新前是否应跟随（由 captureScrollPinState 传入） */
    function scrollChatMessagesToBottomIfPinned(wasPinned) {
        scheduleChatScrollToBottomIfFollowing(wasPinned);
    }

    function forceScrollChatToBottom(smooth) {
        setScrollFollowing();
        cancelAnimationFrame(scrollFollowRaf);
        if (smooth) {
            scrollChatToBottomSmooth();
        } else {
            scrollChatToBottomInstant();
        }
    }

    function onUserSendMessage() {
        setScrollFollowing();
        scrollChatToBottomInstant();
    }

    function clearAllStreamingMarkers() {
        document.querySelectorAll('.progress-container.is-streaming, .process-details-container.is-streaming').forEach(function (el) {
            el.classList.remove('is-streaming');
        });
    }

    function markProgressStreaming(active, progressId) {
        if (!active) {
            clearAllStreamingMarkers();
            return;
        }
        if (!progressId) return;
        const progressEl = document.getElementById(progressId);
        const container = progressEl && progressEl.querySelector('.progress-container');
        if (container) container.classList.add('is-streaming');
    }

    function markProcessDetailsStreaming(active, assistantDomId) {
        if (!active) {
            document.querySelectorAll('.process-details-container.is-streaming').forEach(function (el) {
                el.classList.remove('is-streaming');
            });
            return;
        }
        if (!assistantDomId) return;
        const container = document.getElementById('process-details-' + assistantDomId);
        if (!container) return;
        container.classList.add('is-streaming');
        const timeline = container.querySelector('.progress-timeline');
        if (timeline) timeline.classList.add('expanded');
    }

    function onStreamEnd() {
        clearAllStreamingMarkers();
        try {
            window.__csTaskEventStream = { active: false, conversationId: null, assistantDomId: null, progressId: null };
        } catch (e) { /* ignore */ }
        updateScrollToBottomFab();
    }

    /** 刷新后会话 task-events 补流开始时，与 sendMessage 主流程对齐 */
    function onTaskEventStreamBegin(conversationId, assistantDomId, progressId) {
        try {
            window.__csTaskEventStream = {
                active: true,
                conversationId: conversationId || null,
                assistantDomId: assistantDomId || null,
                progressId: progressId || null
            };
        } catch (e) { /* ignore */ }
        markProcessDetailsStreaming(true, assistantDomId);
        resumeFollowingIfAtBottom();
        updateScrollToBottomFab();
    }

    function onTaskEventStreamEnd() {
        onStreamEnd();
    }

    function applyMessageScrollOption(options) {
        const opt = (options && options.scroll) || 'follow';
        if (opt === 'none') return;
        if (opt === 'force') {
            forceScrollChatToBottom(false);
            return;
        }
        scheduleChatScrollToBottomIfFollowing(captureScrollPinState());
    }

    /** 流式/用户未跟随时禁止 scrollIntoView 抢滚动 */
    function scrollElementIntoViewIfFollowing(el, options) {
        if (!el || !captureScrollPinState()) return;
        el.scrollIntoView(options || { behavior: 'smooth', block: 'nearest' });
    }

    function onChatMessagesScroll() {
        const el = getChatMessagesEl();
        if (!el) return;

        if (programmaticScroll) {
            lastScrollTop = el.scrollTop;
            return;
        }

        const st = el.scrollTop;
        const scrolledUp = st < lastScrollTop - 1;

        if (scrolledUp) {
            setScrollDetached();
        } else if (resumeFollowingIfAtBottom()) {
            /* 拖滚动条/点击轨道跳到底部时也恢复跟随 */
        }

        lastScrollTop = st;
        updateScrollToBottomFab();
    }

    function bindChatScrollListeners() {
        if (listenersBound) return;
        const el = getChatMessagesEl();
        if (!el) return;
        listenersBound = true;
        lastScrollTop = el.scrollTop;

        el.addEventListener('wheel', function (e) {
            if (e.deltaY < -1) setScrollDetached();
        }, { passive: true });

        el.addEventListener('touchmove', function (e) {
            if (e.touches && e.touches.length === 1) {
                el._csTouchLastY = el._csTouchLastY != null ? el._csTouchLastY : e.touches[0].clientY;
                if (e.touches[0].clientY > el._csTouchLastY + 4) {
                    setScrollDetached();
                }
                el._csTouchLastY = e.touches[0].clientY;
            }
        }, { passive: true });
        el.addEventListener('touchstart', function (e) {
            if (e.touches && e.touches.length) {
                el._csTouchLastY = e.touches[0].clientY;
            }
        }, { passive: true });
        el.addEventListener('touchend', function () {
            el._csTouchLastY = null;
        }, { passive: true });

        el.addEventListener('scroll', onChatMessagesScroll, { passive: true });

        const fab = document.getElementById('chat-scroll-to-bottom');
        if (fab) {
            fab.addEventListener('click', function () {
                forceScrollChatToBottom(true);
            });
        }
    }

    function initChatScroll() {
        bindChatScrollListeners();
        const el = getChatMessagesEl();
        if (el) lastScrollTop = el.scrollTop;
        updateScrollToBottomFab();
    }

    window.CyberStrikeChatScroll = {
        init: initChatScroll,
        onUserSendMessage: onUserSendMessage,
        onStreamEnd: onStreamEnd,
        onTaskEventStreamBegin: onTaskEventStreamBegin,
        onTaskEventStreamEnd: onTaskEventStreamEnd,
        captureScrollPinState: captureScrollPinState,
        scheduleScroll: scheduleChatScrollToBottomIfFollowing,
        scrollIfPinned: scrollChatMessagesToBottomIfPinned,
        forceScrollToBottom: forceScrollChatToBottom,
        applyMessageScroll: applyMessageScrollOption,
        scrollIntoViewIfFollowing: scrollElementIntoViewIfFollowing,
        isPinnedToBottom: isChatMessagesPinnedToBottom,
        markProgressStreaming: markProgressStreaming,
        markProcessDetailsStreaming: markProcessDetailsStreaming,
        setScrollFollowing: setScrollFollowing,
        setScrollDetached: setScrollDetached,
    };

    window.isChatMessagesPinnedToBottom = isChatMessagesPinnedToBottom;
    window.captureScrollPinState = captureScrollPinState;
    window.scrollChatMessagesToBottomIfPinned = scrollChatMessagesToBottomIfPinned;

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', initChatScroll);
    } else {
        initChatScroll();
    }
})();
