// @ts-nocheck
import { usePolicyStore } from '../../stores/policy';
import { useModelStore } from '../../stores/model';
import { initializeLegacySocket } from '../../composables/useLegacySocket';
import { renderMarkdown as renderMarkdownHelper } from '../../composables/useMarkdownRenderer';
import {
    scrollToBottom as scrollToBottomHelper,
    conditionalScrollToBottom as conditionalScrollToBottomHelper,
    toggleScrollLock as toggleScrollLockHelper,
    scrollThinkingToBottom as scrollThinkingToBottomHelper
} from '../../composables/useScrollControl';
import {
    startResize as startPanelResize,
    handleResize as handlePanelResize,
    stopResize as stopPanelResize
} from '../../composables/usePanelResize';
import { debugLog } from './common';

export const uiMethods = {
    ensureScrollListener() {
        if (this._scrollListenerReady) {
            return;
        }
        const area = this.getMessagesAreaElement();
        if (!area) {
            return;
        }
        this.initScrollListener();
        this._scrollListenerReady = true;
    },

    setupMobileViewportWatcher() {
        if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
            this.updateMobileViewportState(false);
            return;
        }
        const query = window.matchMedia('(max-width: 768px)');
        this.mobileViewportQuery = query;
        this.updateMobileViewportState(query.matches);
        if (typeof query.addEventListener === 'function') {
            query.addEventListener('change', this.handleMobileViewportQueryChange);
        } else if (typeof query.addListener === 'function') {
            query.addListener(this.handleMobileViewportQueryChange);
        }
    },

    teardownMobileViewportWatcher() {
        const query = this.mobileViewportQuery;
        if (!query) {
            return;
        }
        if (typeof query.removeEventListener === 'function') {
            query.removeEventListener('change', this.handleMobileViewportQueryChange);
        } else if (typeof query.removeListener === 'function') {
            query.removeListener(this.handleMobileViewportQueryChange);
        }
        this.mobileViewportQuery = null;
    },

    handleMobileViewportQueryChange(event) {
        this.updateMobileViewportState(event.matches);
    },

    updateMobileViewportState(isMobile) {
        this.uiSetMobileViewport(!!isMobile);
        if (!isMobile) {
            this.uiSetMobileOverlayMenuOpen(false);
            this.closeMobileOverlay();
        }
    },

    toggleMobileOverlayMenu() {
        if (!this.isMobileViewport) {
            return;
        }
        this.uiToggleMobileOverlayMenu();
    },

    openMobileOverlay(target) {
        if (!this.isMobileViewport) {
            return;
        }
        if (this.activeMobileOverlay === target) {
            this.closeMobileOverlay();
            return;
        }
        if (this.activeMobileOverlay === 'conversation') {
            this.uiSetSidebarCollapsed(true);
        }
        if (target === 'conversation') {
            this.uiSetSidebarCollapsed(false);
        }
        this.uiSetActiveMobileOverlay(target);
        this.uiSetMobileOverlayMenuOpen(false);
    },

    closeMobileOverlay() {
        if (!this.activeMobileOverlay) {
            this.uiCloseMobileOverlay();
            return;
        }
        if (this.activeMobileOverlay === 'conversation') {
            this.uiSetSidebarCollapsed(true);
        }
        this.uiCloseMobileOverlay();
    },

    applyPolicyUiLocks() {
        const policyStore = usePolicyStore();
        const blocks = policyStore.uiBlocks;
        if (blocks.collapse_workspace) {
            this.uiSetWorkspaceCollapsed(true);
        }
        if (blocks.block_virtual_monitor && this.chatDisplayMode === 'monitor') {
            this.uiSetChatDisplayMode('chat');
        }
    },

    isPolicyBlocked(key: string, message?: string) {
        const policyStore = usePolicyStore();
        if (policyStore.uiBlocks[key]) {
            this.uiPushToast({
                title: '已被管理员禁用',
                message: message || '被管理员强制禁用',
                type: 'warning'
            });
            return true;
        }
        return false;
    },

    handleClickOutsideMobileMenu(event) {
        if (!this.isMobileViewport || !this.mobileOverlayMenuOpen) {
            return;
        }
        const trigger = this.$refs.mobilePanelTrigger;
        if (trigger && typeof trigger.contains === 'function' && trigger.contains(event.target)) {
            return;
        }
        this.uiSetMobileOverlayMenuOpen(false);
    },

    handleWorkspaceToggle() {
        if (this.isMobileViewport) {
            return;
        }
        if (this.isPolicyBlocked('collapse_workspace', '工作区已被管理员强制折叠')) {
            this.uiSetWorkspaceCollapsed(true);
            return;
        }
        const nextState = !this.workspaceCollapsed;
        this.uiSetWorkspaceCollapsed(nextState);
        if (nextState) {
            this.uiSetPanelMenuOpen(false);
        }
    },

    handleDisplayModeToggle() {
        if (this.displayModeSwitchDisabled) {
            // 显式提示管理员禁用
            this.isPolicyBlocked('block_virtual_monitor', '虚拟显示器已被管理员禁用');
            return;
        }
        if (this.chatDisplayMode === 'chat' && this.isPolicyBlocked('block_virtual_monitor', '虚拟显示器已被管理员禁用')) {
            return;
        }
        const next = this.chatDisplayMode === 'chat' ? 'monitor' : 'chat';
        this.uiSetChatDisplayMode(next);
    },

    handleMobileOverlayEscape(event) {
        if (event.key !== 'Escape' || !this.isMobileViewport) {
            return;
        }
        if (this.mobileOverlayMenuOpen) {
            this.uiSetMobileOverlayMenuOpen(false);
            return;
        }
        if (this.activeMobileOverlay) {
            this.closeMobileOverlay();
        }
    },

    handleMobileOverlaySelect(conversationId) {
        this.loadConversation(conversationId);
        this.closeMobileOverlay();
    },

    handleMobilePersonalClick() {
        this.closeMobileOverlay();
        this.uiSetMobileOverlayMenuOpen(false);
        this.openPersonalPage();
    },

    toggleSidebar() {
        if (this.isMobileViewport && this.activeMobileOverlay === 'conversation') {
            this.closeMobileOverlay();
            return;
        }
        this.uiToggleSidebar();
    },

    togglePanelMenu() {
        this.uiTogglePanelMenu();
    },

    selectPanelMode(mode) {
        this.uiSetPanelMode(mode);
        this.uiSetPanelMenuOpen(false);
    },

    openPersonalPage() {
        if (this.isPolicyBlocked('block_personal_space', '个人空间已被管理员禁用')) {
            return;
        }
        this.personalizationOpenDrawer();
    },

    fetchTodoList() {
        return this.fileFetchTodoList();
    },

    fetchSubAgents() {
        return this.subAgentFetch();
    },

    async toggleThinkingMode() {
        await this.handleCycleRunMode();
    },

    handleQuickModeToggle() {
        if (!this.isConnected || this.streamingMessage) {
            return;
        }
        this.handleCycleRunMode();
    },

    toggleQuickMenu() {
        if (!this.isConnected) {
            return;
        }
        const opened = this.inputToggleQuickMenu();
        if (!opened) {
            this.modeMenuOpen = false;
            this.modelMenuOpen = false;
        }
    },

    closeQuickMenu() {
        this.inputCloseMenus();
        this.modeMenuOpen = false;
        this.modelMenuOpen = false;
    },

    toggleModeMenu() {
        if (!this.isConnected || this.streamingMessage) {
            return;
        }
        const next = !this.modeMenuOpen;
        this.modeMenuOpen = next;
        if (next) {
            this.modelMenuOpen = false;
        }
        if (next) {
            this.inputSetToolMenuOpen(false);
            this.inputSetSettingsOpen(false);
            if (!this.quickMenuOpen) {
                this.inputOpenQuickMenu();
            }
        }
    },

    toggleModelMenu() {
        if (!this.isConnected || this.streamingMessage) {
            return;
        }
        const next = !this.modelMenuOpen;
        this.modelMenuOpen = next;
        if (next) {
            this.modeMenuOpen = false;
            this.inputSetToolMenuOpen(false);
            this.inputSetSettingsOpen(false);
            if (!this.quickMenuOpen) {
                this.inputOpenQuickMenu();
            }
        }
    },

    toggleHeaderMenu() {
        if (!this.isConnected) return;
        this.headerMenuOpen = !this.headerMenuOpen;
        if (this.headerMenuOpen) {
            this.closeQuickMenu();
            this.inputCloseMenus();
        }
    },

    async handleModeSelect(mode) {
        if (!this.isConnected || this.streamingMessage) {
            return;
        }
        await this.setRunMode(mode);
    },

    async handleHeaderRunModeSelect(mode) {
        await this.handleModeSelect(mode);
        this.closeHeaderMenu();
    },

    async handleModelSelect(key) {
        if (!this.isConnected || this.streamingMessage) {
            return;
        }
        const policyStore = usePolicyStore();
        if (policyStore.isModelDisabled(key)) {
            this.uiPushToast({
                title: '模型被禁用',
                message: '被管理员强制禁用',
                type: 'warning'
            });
            return;
        }
        if (this.conversationHasImages && !['qwen3-vl-plus', 'kimi-k2.5'].includes(key)) {
            this.uiPushToast({
                title: '切换失败',
                message: '当前对话包含图片，仅支持 Qwen3.5 或 Kimi-k2.5',
                type: 'error'
            });
            return;
        }
        const modelStore = useModelStore();
        const prev = this.currentModelKey;
        try {
            const resp = await fetch('/api/model', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ model_key: key })
            });
            const payload = await resp.json();
            if (!resp.ok || !payload.success) {
                throw new Error(payload.error || payload.message || '切换失败');
            }
            const data = payload.data || {};
            modelStore.setModel(data.model_key || key);
            if (data.run_mode) {
                this.runMode = data.run_mode;
                this.thinkingMode = data.thinking_mode ?? (data.run_mode !== 'fast');
            } else {
                // 前端兼容策略：根据模型特性自动调整运行模式
                const currentModel = modelStore.currentModel;
                if (currentModel?.deepOnly) {
                    this.runMode = 'deep';
                    this.thinkingMode = true;
                } else if (currentModel?.fastOnly) {
                    this.runMode = 'fast';
                    this.thinkingMode = false;
                } else {
                    this.thinkingMode = this.runMode !== 'fast';
                }
            }
            this.uiPushToast({
                title: '模型已切换',
                message: modelStore.currentModel?.label || key,
                type: 'success'
            });
        } catch (error) {
            modelStore.setModel(prev);
            const msg = error instanceof Error ? error.message : String(error || '切换失败');
            this.uiPushToast({
                title: '切换模型失败',
                message: msg,
                type: 'error'
            });
        } finally {
            this.modelMenuOpen = false;
            this.inputCloseMenus();
            this.inputSetQuickMenuOpen(false);
        }
    },

    async handleHeaderModelSelect(key, disabled) {
        if (disabled) return;
        await this.handleModelSelect(key);
        this.closeHeaderMenu();
    },

    async handleCycleRunMode() {
        const modes: Array<'fast' | 'thinking' | 'deep'> = ['fast', 'thinking', 'deep'];
        const currentMode = this.resolvedRunMode;
        const currentIndex = modes.indexOf(currentMode);
        const nextMode = modes[(currentIndex + 1) % modes.length];
        await this.setRunMode(nextMode);
    },

    async setRunMode(mode, options = {}) {
        if (!this.isConnected || this.streamingMessage) {
            this.modeMenuOpen = false;
            return;
        }
        const modelStore = useModelStore();
        const fastOnly = modelStore.currentModel?.fastOnly;
        const deepOnly = modelStore.currentModel?.deepOnly;
        if (fastOnly && mode !== 'fast') {
            if (!options.suppressToast) {
                this.uiPushToast({
                    title: '模式不可用',
                    message: '当前模型仅支持快速模式',
                    type: 'warning'
                });
            }
            this.modeMenuOpen = false;
            this.inputCloseMenus();
            return;
        }
        if (deepOnly && mode !== 'deep') {
            if (!options.suppressToast) {
                this.uiPushToast({
                    title: '模式不可用',
                    message: '当前模型仅支持深度思考模式',
                    type: 'warning'
                });
            }
            this.modeMenuOpen = false;
            this.inputCloseMenus();
            return;
        }
        if (mode === this.resolvedRunMode) {
            this.modeMenuOpen = false;
            this.closeQuickMenu();
            return;
        }
        try {
            const response = await fetch('/api/thinking-mode', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ mode })
            });
            const payload = await response.json();
            if (!response.ok || !payload.success) {
                throw new Error(payload.message || payload.error || '切换失败');
            }
            const data = payload.data || {};
            this.thinkingMode = typeof data.thinking_mode === 'boolean' ? data.thinking_mode : mode !== 'fast';
            this.runMode = data.mode || mode;
        } catch (error) {
            console.error('切换运行模式失败:', error);
            const message = error instanceof Error ? error.message : String(error || '未知错误');
            this.uiPushToast({
                title: '切换思考模式失败',
                message: message || '请稍后重试',
                type: 'error'
            });
        } finally {
            this.modeMenuOpen = false;
            this.inputCloseMenus();
        }
    },

    handleInputChange() {
        this.autoResizeInput();
    },

    handleInputFocus() {
        this.inputSetFocused(true);
        this.closeQuickMenu();
    },

    handleInputBlur() {
        this.inputSetFocused(false);
    },

    handleRealtimeTerminalClick() {
        if (!this.isConnected) {
            return;
        }
        if (this.isPolicyBlocked('block_realtime_terminal', '实时终端已被管理员禁用')) {
            return;
        }
        this.openRealtimeTerminal();
    },

    handleFocusPanelToggleClick() {
        if (!this.isConnected) {
            return;
        }
        if (this.isPolicyBlocked('block_focus_panel', '聚焦面板已被管理员禁用')) {
            return;
        }
        this.toggleFocusPanel();
    },

    handleTokenPanelToggleClick() {
        if (!this.currentConversationId) {
            return;
        }
        if (this.isPolicyBlocked('block_token_panel', '用量统计已被管理员禁用')) {
            return;
        }
        this.toggleTokenPanel();
    },

    handleCompressConversationClick() {
        if (this.compressing || this.streamingMessage || !this.isConnected) {
            return;
        }
        if (this.isPolicyBlocked('block_compress_conversation', '压缩对话已被管理员禁用')) {
            return;
        }
        this.compressConversation();
    },

    openReviewDialog() {
        if (this.isPolicyBlocked('block_conversation_review', '对话引用已被管理员禁用')) {
            return;
        }
        if (!this.isConnected) {
            this.uiPushToast({
                title: '无法使用',
                message: '当前未连接，无法生成回顾文件',
                type: 'warning'
            });
            return;
        }
        if (!this.conversations.length && !this.conversationsLoading) {
            this.loadConversationsList();
        }
        const fallback = this.conversations.find((c) => c.id !== this.currentConversationId);
        if (!fallback) {
            this.uiPushToast({
                title: '暂无可用对话',
                message: '没有可供回顾的其他对话记录',
                type: 'info'
            });
            return;
        }
        this.reviewSelectedConversationId = fallback.id;
        this.reviewDialogOpen = true;
        this.reviewPreviewLines = [];
        this.reviewPreviewError = null;
        this.reviewGeneratedPath = null;
        this.loadReviewPreview(fallback.id);
        this.closeQuickMenu();
    },

    closeHeaderMenu() {
        this.headerMenuOpen = false;
    },

    handleReviewSelect(id) {
        if (id === this.currentConversationId) {
            this.uiPushToast({
                title: '无法引用当前对话',
                message: '请选择其他对话生成回顾',
                type: 'warning'
            });
            return;
        }
        this.reviewSelectedConversationId = id;
        this.loadReviewPreview(id);
    },

    async handleConfirmReview() {
        if (this.reviewSubmitting) return;
        if (!this.reviewSelectedConversationId) {
            this.uiPushToast({
                title: '请选择对话',
                message: '请选择要生成回顾的对话记录',
                type: 'info'
            });
            return;
        }
        if (this.reviewSelectedConversationId === this.currentConversationId) {
            this.uiPushToast({
                title: '无法引用当前对话',
                message: '请选择其他对话生成回顾',
                type: 'warning'
            });
            return;
        }
        if (!this.currentConversationId) {
            this.uiPushToast({
                title: '无法发送',
                message: '当前没有活跃对话，无法自动发送提示消息',
                type: 'warning'
            });
            return;
        }

        this.reviewSubmitting = true;
        try {
            const { path, char_count } = await this.generateConversationReview(this.reviewSelectedConversationId);
            if (!path) {
                throw new Error('未获取到生成的文件路径');
            }
            const count = typeof char_count === 'number' ? char_count : 0;
            this.reviewGeneratedPath = path;
            const suggestion =
                count && count <= 10000
                    ? '建议直接完整阅读。'
                    : '建议使用 read 工具进行搜索或分段阅读。';
            if (this.reviewSendToModel) {
                const message = `帮我继续这个任务，对话文件在 ${path}，文件长 ${count || '未知'} 字符，${suggestion} 请阅读文件了解后，不要直接继续工作，而是向我汇报你的理解，然后等我做出指示。`;
                const sent = this.sendAutoUserMessage(message);
                if (sent) {
                    this.reviewDialogOpen = false;
                }
            } else {
                this.uiPushToast({
                    title: '回顾文件已生成',
                    message: path,
                    type: 'success'
                });
            }
        } catch (error) {
            const msg = error instanceof Error ? error.message : String(error || '生成失败');
            this.uiPushToast({
                title: '生成回顾失败',
                message: msg,
                type: 'error'
            });
        } finally {
            this.reviewSubmitting = false;
        }
    },

    async loadReviewPreview(conversationId) {
        this.reviewPreviewLoading = true;
        this.reviewPreviewError = null;
        this.reviewPreviewLines = [];
        try {
            const resp = await fetch(`/api/conversations/${conversationId}/review_preview?limit=${this.reviewPreviewLimit}`);
            const payload = await resp.json().catch(() => ({}));
            if (!resp.ok || !payload?.success) {
                const msg = payload?.message || payload?.error || '获取预览失败';
                throw new Error(msg);
            }
            this.reviewPreviewLines = payload?.data?.preview || [];
        } catch (error) {
            const msg = error instanceof Error ? error.message : String(error || '获取预览失败');
            this.reviewPreviewError = msg;
        } finally {
            this.reviewPreviewLoading = false;
        }
    },

    async generateConversationReview(conversationId) {
        const response = await fetch(`/api/conversations/${conversationId}/review`, {
            method: 'POST'
        });
        const payload = await response.json().catch(() => ({}));
        if (!response.ok || !payload?.success) {
            const msg = payload?.message || payload?.error || '生成失败';
            throw new Error(msg);
        }
        const data = payload.data || payload;
        return {
            path: data.path || data.file_path || data.relative_path,
            char_count: data.char_count ?? data.length ?? data.size ?? 0
        };
    },

    handleClickOutsideQuickMenu(event) {
        if (!this.quickMenuOpen) {
            return;
        }
        const shell = this.getComposerElement('stadiumShellOuter') || this.getComposerElement('compactInputShell');
        if (shell && shell.contains(event.target)) {
            return;
        }
        this.closeQuickMenu();
    },

    handleClickOutsideHeaderMenu(event) {
        if (!this.headerMenuOpen) return;
        const ribbon = this.$refs.titleRibbon as HTMLElement | undefined;
        const menu = this.$refs.headerMenu as HTMLElement | undefined;
        if ((ribbon && ribbon.contains(event.target)) || (menu && menu.contains(event.target))) {
            return;
        }
        this.closeHeaderMenu();
    },

    handleClickOutsidePanelMenu(event) {
        if (!this.panelMenuOpen) {
            return;
        }
        const leftPanel = this.$refs.leftPanel;
        const wrapper = leftPanel && leftPanel.panelMenuWrapper ? leftPanel.panelMenuWrapper : null;
        if (wrapper && wrapper.contains(event.target)) {
            return;
        }
        this.uiSetPanelMenuOpen(false);
    },

    isConversationBlank() {
        if (!Array.isArray(this.messages) || !this.messages.length) return true;
        return !this.messages.some(
            (msg) => msg && (msg.role === 'user' || msg.role === 'assistant')
        );
    },

    pickWelcomeText() {
        const pool = this.blankWelcomePool;
        if (!Array.isArray(pool) || !pool.length) {
            this.blankWelcomeText = '有什么可以帮忙的？';
            return;
        }
        const idx = Math.floor(Math.random() * pool.length);
        this.blankWelcomeText = pool[idx];
    },

    refreshBlankHeroState() {
        const isBlank = this.isConversationBlank();
        const currentConv = this.currentConversationId || 'temp';
        const needNewWelcome =
            !this.blankHeroActive ||
            this.lastBlankConversationId !== currentConv;

        if (isBlank) {
            if (needNewWelcome && !this.blankHeroExiting) {
                this.pickWelcomeText();
            }
            this.blankHeroActive = true;
            this.lastBlankConversationId = currentConv;
        } else {
            this.blankHeroActive = false;
            this.blankHeroExiting = false;
            this.lastBlankConversationId = null;
        }
    },

    toggleSettings() {
        if (!this.isConnected) {
            return;
        }
        this.modeMenuOpen = false;
        this.modelMenuOpen = false;
        const nextState = this.inputToggleSettingsMenu();
        if (nextState) {
            this.inputSetToolMenuOpen(false);
            if (!this.quickMenuOpen) {
                this.inputOpenQuickMenu();
            }
        }
    },

    toggleFocusPanel() {
        this.rightCollapsed = !this.rightCollapsed;
        if (!this.rightCollapsed && this.rightWidth < this.minPanelWidth) {
            this.rightWidth = this.minPanelWidth;
        }
    },

    addSystemMessage(content) {
        this.chatAddSystemMessage(content);
        this.$forceUpdate();
        this.conditionalScrollToBottom();
    },

    startTitleTyping(title: string, options: { animate?: boolean } = {}) {
        if (this.titleTypingTimer) {
            clearInterval(this.titleTypingTimer);
            this.titleTypingTimer = null;
        }
        const target = (title || '').trim();
        const animate = options.animate ?? true;
        if (!animate) {
            this.titleTypingTarget = target;
            this.titleTypingText = target;
            return;
        }
        const previous = (this.titleTypingText || '').trim();
        if (previous === target) {
            this.titleTypingTarget = target;
            this.titleTypingText = target;
            return;
        }
        this.titleTypingTarget = target;
        this.titleTypingText = previous;

        const frames: string[] = [];
        for (let i = previous.length; i >= 0; i--) {
            frames.push(previous.slice(0, i));
        }
        for (let j = 1; j <= target.length; j++) {
            frames.push(target.slice(0, j));
        }

        let index = 0;
        this.titleTypingTimer = window.setInterval(() => {
            if (index >= frames.length) {
                clearInterval(this.titleTypingTimer!);
                this.titleTypingTimer = null;
                this.titleTypingText = target;
                return;
            }
            this.titleTypingText = frames[index];
            index += 1;
        }, 32);
    },

    toggleBlock(blockId) {
        if (!blockId) {
            return;
        }
        if (this.expandedBlocks && this.expandedBlocks.has(blockId)) {
            this.chatCollapseBlock(blockId);
        } else {
            this.chatExpandBlock(blockId);
        }
    },

    handleThinkingScroll(blockId, event) {
        if (!blockId || !event || !event.target) {
            return;
        }
        const el = event.target;
        const threshold = 12;
        const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < threshold;
        this.chatSetThinkingLock(blockId, atBottom);
    },

    scrollToBottom() {
        scrollToBottomHelper(this);
    },

    conditionalScrollToBottom() {
        conditionalScrollToBottomHelper(this);
    },

    toggleScrollLock() {
        toggleScrollLockHelper(this);
    },

    scrollThinkingToBottom(blockId) {
        scrollThinkingToBottomHelper(this, blockId);
    },

    // 面板调整方法
    startResize(panel, event) {
        startPanelResize(this, panel, event);
    },

    handleResize(event) {
        handlePanelResize(this, event);
    },

    stopResize() {
        stopPanelResize(this);
    },

    getInputComposerRef() {
        return this.$refs.inputComposer || null;
    },

    getComposerElement(field) {
        const composer = this.getInputComposerRef();
        const unwrap = (value: any) => {
            if (!value) {
                return null;
            }
            if (value instanceof HTMLElement) {
                return value;
            }
            if (typeof value === 'object' && 'value' in value && !(value instanceof Window)) {
                return value.value;
            }
            return value;
        };
        if (composer && composer[field]) {
            return unwrap(composer[field]);
        }
        if (this.$refs && this.$refs[field]) {
            return unwrap(this.$refs[field]);
        }
        return null;
    },

    getMessagesAreaElement() {
        const ref = this.$refs.messagesArea;
        if (!ref) {
            return null;
        }
        if (ref instanceof HTMLElement) {
            return ref;
        }
        if (ref.rootEl) {
            return ref.rootEl.value || ref.rootEl;
        }
        if (ref.$el && ref.$el.querySelector) {
            const el = ref.$el.querySelector('.messages-area');
            if (el) {
                return el;
            }
        }
        return null;
    },

    getThinkingContentElement(blockId) {
        const chatArea = this.$refs.messagesArea;
        if (chatArea && typeof chatArea.getThinkingRef === 'function') {
            const el = chatArea.getThinkingRef(blockId);
            if (el) {
                return el;
            }
        }
        const refName = `thinkingContent-${blockId}`;
        const elRef = this.$refs[refName];
        if (Array.isArray(elRef)) {
            return elRef[0] || null;
        }
        return elRef || null;
    },

    isOutputActive() {
        return !!(this.streamingMessage || this.taskInProgress || this.hasPendingToolActions());
    },

    logMessageState(action, extra = {}) {
        const count = Array.isArray(this.messages) ? this.messages.length : 'N/A';
        debugLog('[Messages]', {
            action,
            count,
            conversationId: this.currentConversationId,
            streaming: this.streamingMessage,
            ...extra
        });
    },

    iconStyle(iconKey, size) {
        const iconPath = this.icons ? this.icons[iconKey] : null;
        if (!iconPath) {
            return {};
        }
        const style = { '--icon-src': `url(${iconPath})` };
        if (size) {
            style['--icon-size'] = size;
        }
        return style;
    },

    openGuiFileManager() {
        if (this.isPolicyBlocked('block_file_manager', '文件管理器已被管理员禁用')) {
            return;
        }
        window.open('/file-manager', '_blank');
    },

    renderMarkdown(content, isStreaming = false) {
        return renderMarkdownHelper(content, isStreaming);
    },

    async bootstrapRoute() {
        // 在路由解析期间抑制标题动画，避免预置“新对话”闪烁
        this.suppressTitleTyping = true;
        this.titleReady = false;
        this.currentConversationTitle = '';
        this.titleTypingText = '';
        const path = window.location.pathname.replace(/^\/+/, '');
        if (!path || path === 'new') {
            this.currentConversationId = null;
            this.currentConversationTitle = '新对话';
            this.titleReady = true;
            this.suppressTitleTyping = false;
            this.startTitleTyping('新对话', { animate: false });
            this.initialRouteResolved = true;
            return;
        }

        const convId = path.startsWith('conv_') ? path : `conv_${path}`;
        try {
            const resp = await fetch(`/api/conversations/${convId}/load`, { method: 'PUT' });
            const result = await resp.json();
            if (result.success) {
                this.currentConversationId = convId;
                this.currentConversationTitle = result.title || '';
                this.titleReady = true;
                this.suppressTitleTyping = false;
                this.startTitleTyping(this.currentConversationTitle, { animate: false });
                history.replaceState({ conversationId: convId }, '', `/${this.stripConversationPrefix(convId)}`);
            } else {
                history.replaceState({}, '', '/new');
                this.currentConversationId = null;
                this.currentConversationTitle = '新对话';
                this.titleReady = true;
                this.suppressTitleTyping = false;
                this.startTitleTyping('新对话', { animate: false });
            }
        } catch (error) {
            console.warn('初始化路由失败:', error);
            history.replaceState({}, '', '/new');
            this.currentConversationId = null;
            this.currentConversationTitle = '新对话';
            this.titleReady = true;
            this.suppressTitleTyping = false;
            this.startTitleTyping('新对话', { animate: false });
        } finally {
            this.initialRouteResolved = true;
        }
    },

    handlePopState(event) {
        const state = event.state || {};
        const convId = state.conversationId;
        if (!convId) {
            this.currentConversationId = null;
            this.currentConversationTitle = '新对话';
            this.logMessageState('handlePopState:clear-messages-no-conversation');
            this.messages = [];
            this.logMessageState('handlePopState:after-clear-no-conversation');
            this.resetAllStates('handlePopState:no-conversation');
            this.resetTokenStatistics();
            return;
        }
        this.loadConversation(convId);
    },

    stripConversationPrefix(conversationId) {
        if (!conversationId) return '';
        return conversationId.startsWith('conv_') ? conversationId.slice(5) : conversationId;
    },

    initScrollListener() {
        const messagesArea = this.getMessagesAreaElement();
        if (!messagesArea) {
            console.warn('消息区域未找到');
            return;
        }
        this._scrollListenerReady = true;

        let isProgrammaticScroll = false;
        const bottomThreshold = 12;

        this._setScrollingFlag = (flag) => {
            isProgrammaticScroll = !!flag;
        };

        messagesArea.addEventListener('scroll', () => {
            if (isProgrammaticScroll) {
                return;
            }

            const scrollTop = messagesArea.scrollTop;
            const scrollHeight = messagesArea.scrollHeight;
            const clientHeight = messagesArea.clientHeight;
            const isAtBottom = scrollHeight - scrollTop - clientHeight < bottomThreshold;

            const activeLock = this.autoScrollEnabled && this.isOutputActive();

            // 锁定且当前有输出时，强制贴底
            if (activeLock) {
                if (!isAtBottom) {
                    if (typeof this._setScrollingFlag === 'function') {
                        this._setScrollingFlag(true);
                    }
                    messagesArea.scrollTop = messagesArea.scrollHeight;
                    if (typeof this._setScrollingFlag === 'function') {
                        setTimeout(() => this._setScrollingFlag && this._setScrollingFlag(false), 16);
                    }
                }
                // 保持锁定状态下 userScrolling 为 false
                this.chatSetScrollState({ userScrolling: false });
                return;
            }

            // 未锁定或无输出：允许自由滚动，仅记录位置
            this.chatSetScrollState({ userScrolling: !isAtBottom });
        });
    },

    async initSocket() {
        await initializeLegacySocket(this);
    },

    openRealtimeTerminal() {
        const { protocol, hostname, port } = window.location;
        const target = `${protocol}//${hostname}${port ? ':' + port : ''}/terminal`;
        window.open(target, '_blank');
    },

    async loadInitialData() {
        try {
            debugLog('加载初始数据...');

            const statusResponse = await fetch('/api/status');
            const statusData = await statusResponse.json();
            this.projectPath = statusData.project_path || '';
            this.agentVersion = statusData.version || this.agentVersion;
            this.thinkingMode = !!statusData.thinking_mode;
            this.applyStatusSnapshot(statusData);
            // 立即更新配额和运行模式，避免等待其他慢接口
            this.fetchUsageQuota();
            // 拉取管理员策略
            const policyStore = usePolicyStore();
            await policyStore.fetchPolicy();
            this.applyPolicyUiLocks();

            const focusPromise = this.focusFetchFiles();
            const todoPromise = this.fileFetchTodoList();
            let treePromise: Promise<any> | null = null;
            const isHostMode = statusData?.container?.mode === 'host';
            if (isHostMode) {
                this.fileMarkTreeUnavailable('宿主机模式下文件树不可用');
            } else {
                treePromise = this.fileFetchTree();
            }

            // 获取当前对话信息
            const statusConversationId = statusData.conversation && statusData.conversation.current_id;
            if (statusConversationId && !this.currentConversationId) {
                this.skipConversationHistoryReload = true;
                // 首次从状态恢复对话时，避免 socket 的 conversation_loaded 再次触发历史加载
                this.skipConversationLoadedEvent = true;
                this.suppressTitleTyping = true;
                this.titleReady = false;
                this.currentConversationTitle = '';
                this.titleTypingText = '';
                this.currentConversationId = statusConversationId;

                // 如果有当前对话，尝试获取标题和历史
                try {
                    const convResponse = await fetch(`/api/conversations/current`);
                    const convData = await convResponse.json();
                    if (convData.success && convData.data) {
                        this.currentConversationTitle = convData.data.title;
                        this.titleReady = true;
                        this.suppressTitleTyping = false;
                        this.startTitleTyping(this.currentConversationTitle, { animate: false });
                    } else {
                        this.titleReady = true;
                        this.suppressTitleTyping = false;
                        const fallbackTitle = this.currentConversationTitle || '新对话';
                        this.currentConversationTitle = fallbackTitle;
                        this.startTitleTyping(fallbackTitle, { animate: false });
                    }
                    // 初始化时调用一次，因为 skipConversationHistoryReload 会阻止 watch 触发
                    if (
                        this.lastHistoryLoadedConversationId !== this.currentConversationId ||
                        !Array.isArray(this.messages) ||
                        this.messages.length === 0
                    ) {
                        await this.fetchAndDisplayHistory();
                    }
                    // 获取当前对话的Token统计
                    this.fetchConversationTokenStatistics();
                    this.updateCurrentContextTokens();
                } catch (e) {
                    console.warn('获取当前对话标题失败:', e);
                    this.titleReady = true;
                    this.suppressTitleTyping = false;
                    this.startTitleTyping(this.currentConversationTitle || '新对话', '');
                }
            }

            // 等待其他加载项完成（允许部分失败不阻塞模式切换）
            const pendingPromises = [focusPromise, todoPromise];
            if (treePromise) {
                pendingPromises.push(treePromise);
            }
            await Promise.allSettled(pendingPromises);
            await this.loadToolSettings(true);

            debugLog('初始数据加载完成');
        } catch (error) {
            console.error('加载初始数据失败:', error);
        }
    },

    confirmAction(options = {}) {
        return this.uiRequestConfirm(options);
    }
};
