<template>
    <view class="chat-container">
        <!-- 选择模式操作栏 -->
        <view v-if="isSelectMode" class="select-mode-header">
            <view class="select-header-left">
                <view class="select-count">{{ selectedMessages.length }} 条已选择</view>
                <view class="select-all" @click="selectAllMessages">全选</view>
            </view>
            <view class="select-header-right">
                <view class="cancel-btn" @click="exitSelectMode">取消</view>
                <view class="delete-btn" @click="deleteSelectedMessages" :disabled="selectedMessages.length === 0">删除</view>
            </view>
        </view>
        <!-- Tab切换 -->
        <view v-else class="tab-container">
            <view 
                class="tab-item" 
                :class="{ active: activeTab === 'policy' }"
                @click="switchTab('policy')"
            >
                政策查询
            </view>
            <view 
                class="tab-item" 
                :class="{ active: activeTab === 'job' }"
                @click="switchTab('job')"
            >
                岗位推荐
            </view>
        </view>
        
        <!-- #ifdef MP-WEIXIN -->
         <view class="chat-background" v-if="!messages.length">
            <image class="backlogo" src="/static/icon/backAI.png"></image>
            <view class="back-rowTitle">嗨！欢迎使用{{ config.appInfo.areaName }}AI智能求职</view>
            <view class="back-rowText">
                我可以根据您的简历和求职需求，帮你精准匹配{{ config.appInfo.areaName }}互联网招聘信息，对比招聘信息的优缺点，提供面试指导等，请把你的任务交给我吧~
            </view>
            <view class="back-rowh3">猜你所想</view>
            <view
                class="back-rowmsg button-click"
                v-for="(item, index) in queries"
                :key="index"
                @click="sendMessageGuess(item)"
            >
                {{ item }}
            </view>
            <view class="chat-item self" v-if="isRecording">
                <view class="message">{{ recognizedText }} {{ lastFinalText }}</view>
            </view>
        </view>
        <!-- #endif -->
        <!-- #ifndef MP-WEIXIN -->
        <view class="chat-background" v-if="!messages.length">
            <image class="backlogo" src="/static/icon/backAI.png"></image>
            <view class="back-rowTitle">嗨！欢迎使用{{ config.appInfo.areaName }}AI智能求职</view>
            <view class="back-rowText">
                我可以根据您的简历和求职需求，帮你精准匹配{{ config.appInfo.areaName }}互联网招聘信息，对比招聘信息的优缺点，提供面试指导等，请把你的任务交给我吧~
            </view>
            <view class="back-rowh3">猜你所想</view>
            <view
                class="back-rowmsg button-click"
                v-for="(item, index) in queries"
                :key="index"
                @click="sendMessageGuess(item)"
            >
                {{ item }}
            </view>
            <view class="chat-item self" v-if="isRecording">
                <view class="message">{{ recognizedText }} {{ lastFinalText }}</view>
            </view>
        </view>
        <!-- #endif -->
        <scroll-view class="chat-list scrollView" :scroll-top="scrollTop" :scroll-y="true" scroll-with-animation>
            <!-- #ifdef MP-WEIXIN -->
            <view class="chat-list list-content">
            <!-- #endif -->
            <!-- #ifndef MP-WEIXIN -->
            <view class="chat-list list-content" v-fade:600="messages.length >= 1">
            <!-- #endif -->
                <view
                    v-for="(msg, index) in messages"
                    v-show="shouldShowMessage(msg)"
                    :key="index"
                    :id="'msg-' + index"
                    class="chat-item"
                    :class="{ self: msg.self }"
                    @longpress="handleLongPress(msg, index)"
                    @click="isSelectMode ? toggleSelectMessage(index) : null"
                >
                    <!-- 选择框 -->
                    <view v-if="isSelectMode" class="message-checkbox">
                        <view class="checkbox" :class="{ checked: selectedMessages.includes(index) }">
                            <uni-icons v-if="selectedMessages.includes(index)" type="success" size="24" color="#FFFFFF"></uni-icons>
                        </view>
                    </view>
                    <view class="message" v-if="msg.self">
                        <view class="msg-filecontent" v-if="msg.files.length">
                            <view
                                class="msg-files btn-light"
                                v-for="(file, vInex) in msg.files"
                                :key="vInex"
                                @click="jumpUrl(file)"
                                :class="{ 'msg-image-file': isImage(file.type, file.name) }"
                            >
                                <image 
                                        v-if="isImage(file.type, file.name)" 
                                        class="msg-image-thumbnail" 
                                        :src="file.url" 
                                        mode="aspectFill"
                                    ></image>
                                <image 
                                    v-else 
                                    class="msg-file-icon" 
                                    src="/static/icon/Vector2.png"
                                ></image>
                                <text class="msg-file-text">{{ file.name || '附件' }}</text>
                            </view>
                        </view>
                        {{ msg.displayText }}
                    </view>
                    <view class="message" :class="{ messageNull: !msg.displayText }" v-else>
                        <!-- {{ msg.displayText }} -->
                        <view class="message-markdown">
                            <md-render
                                :content="msg.displayText"
                                :typing="isTyping && messages.length - 1 === index"
                            ></md-render>
                            <view class="message-controll" v-show="showControll(index) && !isSelectMode">
                                <view class="controll-left">
                                    <image
                                        class="controll-icon btn-light"
                                        src="/static/icon/copy.png"
                                        @click="copyMarkdown(msg.displayText)"
                                    ></image>
                                    <image
                                        class="controll-icon mar_le10 btn-light"
                                        src="/static/icon/feedback.png"
                                        v-if="!msg.userBadFeedback"
                                        @click="userGoodFeedback(msg)"
                                    ></image>
                                    <image
                                        v-if="isSpeaking && !isPaused && speechIndex === index"
                                        class="controll-icon mar_le10 btn-light"
                                        src="/static/icon/stop.png"
                                        @click="stopMarkdown(msg.displayText, index)"
                                    ></image>
                                    <image
                                        class="controll-icon mar_le10 btn-light"
                                        src="/static/icon/broadcast.png"
                                        @click="readMarkdown(msg.displayText, index)"
                                        v-else
                                    ></image>
                                </view>
                                <view class="controll-right">
                                    <image
                                        class="controll-icon mar_ri10 btn-light"
                                        src="/static/icon/refresh.png"
                                        @click="refreshMarkdown(index)"
                                    ></image>
                                </view>
                            </view>
                        </view>
                        <!-- guess -->
                        <view
                            class="guess"
                            v-if="showGuess && !msg.self && messages.length - 1 === index && msg.displayText && !isSelectMode"
                        >
                            <view class="gulist">
                                <view
                                    class="guess-list"
                                    @click="sendMessageGuess(item)"
                                    v-for="(item, index) in guessList"
                                    :key="index"
                                >
                                    {{ item }}
                                </view>
                            </view>
                        </view>
                    </view>
                </view>
                <view class="chat-item self" v-if="isRecording">
                    <view class="message">{{ recognizedText }} {{ lastFinalText }}</view>
                </view>
                <!-- 语音正在识别提示 -->
                <!-- <view>{{isRecognizing}}</view> -->
                <view class="chat-item self" v-if="isRecognizing">
                    <view class="message msg-loading">
                        <view class="loading-content">
                            <view class="ai-loading">
                                <view></view>
                                <view></view>
                                <view></view>
                            </view>
                            <text class="loading-text">正在识别语音...</text>
                        </view>
                    </view>
                </view>
                <view v-if="isTyping" class="self">
                    <view class="message msg-loading">
                        <view class="loading-content">
                            <view class="ai-loading">
                                <view></view>
                                <view></view>
                                <view></view>
                            </view>
                            <text class="loading-text">AI正在思考中...</text>
                        </view>
                    </view>
                </view>
            </view>
        </scroll-view>
        <!-- 使用 v-show 保证不销毁事件 -->
        <view class="vio_container" :class="status" v-show="status !== 'idle'">
            <view class="record-tip">{{ statusText }}</view>
            <WaveDisplay
                :background="audiowaveStyle"
                :isActive="isRecording"
                :audioData="audioDataForDisplay"
                :showInfo="isRecording"
            />
        </view>
        <view class="input-area" v-show="status === 'idle'">
            <view class="areatext">
                <input
                    v-model="textInput"
                    placeholder-class="inputplaceholder"
                    class="input"
                    @confirm="sendMessage"
                    :disabled="isTyping"
                    :adjust-position="true"
                    placeholder="请输入您想找的岗位信息或就政策信息【比如:设计师、10000-12000、广州】【比如:今年喀什地区高校毕业生有什么就业政策】"
                    v-show="!isVoice"
                />
                <view
                    class="input_vio"
                    @touchstart.prevent="handleTouchStart"
                    @touchmove="handleTouchMove"
                    @touchend="handleTouchEnd"
                    @touchcancel="handleTouchCancel"
                    v-show="isVoice"
                    type="default"
                >
                    按住说话
                </view>
                <!-- upload -->
                <view class="btn-box" @click="changeShowFile">
                    <image
                        class="send-btn"
                        :class="{ 'add-file-btn': showfile }"
                        src="/static/icon/addGroup.png"
                    ></image>
                </view>
                <!-- sendmessgae  Button-->
                <view class="btn-box purple" v-if="textInput && !isTyping" @click="sendMessage">
                    <image class="send-btn" src="/static/icon/send3.png"></image>
                </view>
                <view class="btn-box" v-else-if="!isTyping && !isVoice" @click="changeVoice">
                    <image class="send-btn" src="/static/icon/send2x.png"></image>
                </view>
                <view class="btn-box" v-else-if="!isTyping" @click="changeVoice">
                    <image class="send-btn" src="/static/icon/send4.png"></image>
                </view>
                <view class="btn-box purple" v-else>
                    <view class="btn-box-round"></view>
                </view>
            </view>
            <view class="ai-tips">本服务为AI生成内容，结果仅供参考</view>
            <!-- 文件上传区域 - 使用绝对定位向上展开，避免被tabbar遮挡 -->
            <view class="file-upload-popup" :class="{ show: showfile }">
                <view class="area-tips">
                    <uni-icons type="info-filled" color="#ADADAD" size="15"></uni-icons>
                    上传后自动解析简历内容
                </view>
                <view class="area-file">
                    <view class="file-card" @click="uploadCamera">
                        <image class="card-img" src="/static/icon/file1.png"></image>
                        <text>拍照上传</text>
                    </view>
                    <view class="file-card" @click="uploadCamera('album')">
                        <image class="card-img" src="/static/icon/file2.png"></image>
                        <text>相册上传</text>
                    </view>
                    <view class="file-card" @click="getUploadFile">
                        <image class="card-img" src="/static/icon/file3.png"></image>
                        <text>文件上传</text>
                    </view>
                </view>
            </view>

            <!-- filelist -->
            <view class="area-uploadfiles" v-if="filesList.length">
                <scroll-view class="uploadfiles-scroll" scroll-x="true">
                    <view class="uploadfiles-list">
                        <view
                            class="file-uploadsend"
                            :class="{ 'file-border': isImage(file.type, file.name) }"
                            v-for="(file, index) in filesList"
                            :key="index"
                        >
                            <view class="file-thumbnail" @click="jumpUrl(file)">
                                <image
                                    class="file-iconImg"
                                    v-if="isImage(file.type, file.name) && !file.error"
                                    :src="file.tempPath || file.url"
                                    mode="aspectFill"
                                    @load="onImageLoad(file)"
                                    @error="onImageError(file)"
                                ></image>
                                <view class="file-doc" v-else-if="!isImage(file.type, file.name)">
                                    <FileIcon class="doc-icon" :type="file.type"></FileIcon>
                                </view>
                                <view class="image-loading" v-if="isImage(file.type, file.name) && file.loading">
                                    <uni-icons type="spinner-cycle" size="30" color="#999"></uni-icons>
                                    <text class="loading-text">加载中...</text>
                                </view>
                                <view class="image-error" v-if="isImage(file.type, file.name) && file.error" @click="retryImageLoad(file)">
                                    <uni-icons type="info" size="30" color="#ff4444"></uni-icons>
                                    <text class="error-text">加载失败</text>
                                    <text class="retry-text">点击重试</text>
                                </view>
                                <!-- 图片数量标签 -->
                                <view class="image-count-badge" v-if="isImage(file.type, file.name) && filesList.filter(f => isImage(f.type, f.name)).length > 1">
                                    {{ filesList.filter(f => isImage(f.type, f.name)).indexOf(file) + 1 }}/{{ filesList.filter(f => isImage(f.type, f.name)).length }}
                                </view>
                            </view>
                            <view class="file-info">
                                <view class="filename-text">{{ file.name }}</view>
                                <view class="filerow" v-if="!isImage(file.type, file.name)">
                                    <FileText :type="file.type"></FileText>
                                    <view class="row-x"></view>
                                    <view class="filename-size">{{ file.size }}</view>
                                </view>
                                <view class="filerow" v-else>
                                    <text class="file-type-tag">图片</text>
                                    <view class="row-x"></view>
                                    <view class="filename-size">{{ file.size }}</view>
                                </view>
                            </view>
                            <view class="file-del" catchtouchmove="true" @click="delfile(file)">
                                <uni-icons type="closeempty" color="#FFFFFF" size="10"></uni-icons>
                            </view>
                        </view>
                    </view>
                </scroll-view>
            </view>
        </view>
        <PopupFeeBack ref="feeback" @onSend="confirmFeeBack"></PopupFeeBack>
        <MsgTips ref="feeBackTips" content="已收到反馈，感谢您的关注" title="反馈成功" :icon="successIcon"></MsgTips>
    </view>
</template>

<script setup>
import {
    ref,
    inject,
    nextTick,
    onMounted,
    onUnmounted,
    toRaw,
    reactive,
    computed,
    watch,
    getCurrentInstance,
} from 'vue';
import { storeToRefs } from 'pinia';
// 移除重复导入，使用从globalFunction注入的config
import useChatGroupDBStore from '@/packageA/stores/userChatGroupStore';
import MdRender from '@/packageA/components/md-render/md-render.vue';
import PopupFeeBack from './popupbadFeeback.vue';
import AudioWave from './AudioWave.vue';
import WaveDisplay from './WaveDisplay.vue';
import FileIcon from './fileIcon.vue';
import FileText from './fileText.vue';
import { useAudioRecorder } from '@/packageA/hook/useRealtimeRecorder.js';
import { useTTSPlayer } from '@/packageA/hook/useTTSPlayer.js';
import successIcon from '@/static/icon/success.png';
// 全局
const { $api, navTo, throttle, config } = inject('globalFunction');
const emit = defineEmits(['onConfirm']);
const { messages, isTyping, textInput, chatSessionID } = storeToRefs(useChatGroupDBStore());
// hook
const {
    isRecording,
    startRecording,
    stopRecording,
    cancelRecording,
    audioDataForDisplay,
    volumeLevel,
    recognizedText,
    lastFinalText,
    recordingDuration,
    isRecognizing,
    reset
} = useAudioRecorder();

// 监听语音识别结果变化，自动发送消息
watch(
    () => recognizedText.value,
    (newVal) => {
        if (newVal && newVal.trim()) {
            console.log('监听到语音识别结果变化，自动发送消息:', newVal);
            sendMessage(newVal);
        }
    }
);

// 监听isRecognizing状态，显示提示
watch(
    () => isRecognizing.value,
    (newVal) => {
        if (newVal) {
            $api.msg('正在识别语音...');
        }
    }
);

const { speak, pause, resume, isSpeaking, isPaused, cancelAudio } = useTTSPlayer(config.speechSynthesis);

// 获取组件实例（用于小程序 SelectorQuery）
const instance = getCurrentInstance();

// state
const activeTab = ref('policy'); // 'policy' or 'job'
const queries = ref([]);
const guessList = ref([]);
const scrollTop = ref(0);
const showGuess = ref(false);
const showfile = ref(false);
const filesList = ref([]);
const bgText = ref(false);
const isVoice = ref(false);
const status = ref('idle'); // idle | recording | cancel
const startY = ref(0);
const cancelThreshold = 100;
const speechIndex = ref(0);
const isAudioPermission = ref(false);
const feebackData = ref(null);
// 删除功能相关状态
const isSelectMode = ref(false);
const selectedMessages = ref([]);
// ref for DOM element
const voiceBtn = ref(null);
const feeback = ref(null);
const feeBackTips = ref(null);
const state = reactive({
    uploadFileTips: '请根据以上附件，帮我推荐岗位。',
});

const statusText = computed(() => {
    switch (status.value) {
        case 'recording':
            return '松手发送，上划取消';
        case 'cancel':
            return '松手取消';
        default:
            return '按住说话';
    }
});

const audiowaveStyle = computed(() => {
    return status.value === 'cancel'
        ? '#f54545'
        : status.value === 'recording'
        ? 'linear-gradient(to right, #377dff, #9a60ff)'
        : '#f1f1f1';
});

onMounted(async () => {
    changeQueries();
    scrollToBottom();
    isAudioPermission.value = await requestMicPermission();
    reset(); // 重置语音识别状态
});

const requestMicPermission = async () => {
    // #ifdef H5
    try {
        if (typeof navigator !== 'undefined' && navigator.mediaDevices) {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            console.log('✅ 麦克风权限已授权');

            // 立刻停止所有音轨，释放麦克风
            stream.getTracks().forEach((track) => track.stop());

            return true;
        } else {
            console.warn('❌ 当前环境不支持麦克风');
            return false;
        }
    } catch (err) {
        console.warn('❌ 用户拒绝麦克风权限或不支持:', err);
        return false;
    }
    // #endif
    
    // #ifdef MP-WEIXIN
    try {
        // 微信小程序使用 uni.authorize 请求权限
        const res = await uni.authorize({
            scope: 'scope.record'
        });
        console.log('✅ 麦克风权限已授权');
        return true;
    } catch (err) {
        console.warn('❌ 用户拒绝麦克风权限:', err);
        // 用户拒绝授权，但不影响其他功能
        return false;
    }
    // #endif
    
    // #ifndef H5 || MP-WEIXIN
    // 其他平台暂不支持
    console.warn('❌ 当前平台不支持麦克风权限检测');
    return false;
    // #endif
};

function showControll(index) {
    if (index === messages.value.length - 1 && isTyping.value) {
        return false;
    }
    return true;
}

const sendMessage = (text) => {
    const values = textInput.value || text;
    showfile.value = false;
    showGuess.value = false;
    if (values.trim()) {
        // 判断是否有对话ID // 没有则创建对话列表
        const callback = () => {
            const normalArr = toRaw(filesList.value); // 转换为普通数组
            filesList.value = [];
            useChatGroupDBStore()
                .getStearm(values, normalArr, scrollToBottom, {
                    onDataReceived: (data, message, index) => {
                        // 流式朗读：只在内容足够长且包含完整信息时才开始朗读
                        if (!message.self && message.displayText && message.displayText.trim()) {
                            // 检查是否已经开始朗读这条消息
                            if (speechIndex.value !== index) {
                                // 延迟TTS，等待内容更完整
                                // 只有在内容长度超过50个字符或者包含岗位信息时才开始朗读
                                const hasJobInfo = message.displayText.includes('```job-json') || 
                                                 message.displayText.includes('岗位') ||
                                                 message.displayText.includes('公司') ||
                                                 message.displayText.includes('薪资');
                                
                                if (message.displayText.length > 50 || hasJobInfo) {
                                    console.log('🎵 Starting streaming TTS for message index:', index);
                                    console.log('📝 Current text length:', message.displayText.length);
                                    console.log('📝 Has job info:', hasJobInfo);
                                    
                                    // 开始朗读当前消息
                            speechIndex.value = index;
                            readMarkdown(message.displayText, index, { immediate: false });
                            // 一旦开始朗读，就设置speechIndex，避免重复调用
                            speechIndex.value = index;
                                } else {
                                    console.log('⏳ Waiting for more content before TTS, current length:', message.displayText.length);
                                }
                            } else {
                                // 已经开始朗读这条消息，不再重复调用
                                console.log('⏭️ Already speaking this message, skipping duplicate TTS call');
                            }
                        }
                    },
                    onComplete: () => {
                        console.log('🎯 onComplete callback triggered');
                        console.log('📊 Messages array length:', messages.value.length);
                        
                        // 确保最后一条AI消息的朗读完成
                        const lastMessageIndex = messages.value.length - 1;
                        if (lastMessageIndex >= 0) {
                            const lastMessage = messages.value[lastMessageIndex];
                            if (!lastMessage.self && lastMessage.displayText && lastMessage.displayText.trim()) {
                                console.log('🎵 Final TTS for complete message');
                                console.log('📝 Final text length:', lastMessage.displayText.length);
                                console.log('📝 Final text preview:', lastMessage.displayText.substring(0, 100) + '...');
                                
                                // 停止当前的朗读（如果有的话）
                                if (isSpeaking.value) {
                                    console.log('🛑 Stopping current TTS to start final complete TTS');
                                    cancelAudio();
                                }
                                
                                // 开始朗读完整的内容
                                speechIndex.value = lastMessageIndex;
                                readMarkdown(lastMessage.displayText, lastMessageIndex, { immediate: true });
                            }
                        }
                    },
                })
                .then(() => {
                    getGuess();
                    scrollToBottom();
                });
            emit('onConfirm', values);
            textInput.value = '';
            scrollToBottom();
        };
        // 没有对话列表则创建
        if (!chatSessionID.value) {
            useChatGroupDBStore()
                .addTabel(values)
                .then((res) => {
                    callback();
                });
        } else {
            callback();
        }
    } else {
        if (filesList.value.length) {
            $api.msg('上传文件请输入想问的问题描述');
        } else {
            $api.msg('请输入职位信息或描述');
        }
    }
};

const sendMessageGuess = (item) => {
    showGuess.value = false;
    textInput.value = item;
    sendMessage(item);
};

const delfile = (file) => {
    uni.showModal({
        content: '确认删除文件？',
        success(res) {
            if (res.confirm) {
                filesList.value = filesList.value.filter((item) => item.url !== file.url);
                if (!filesList.value.length) {
                    if (textInput.value === state.uploadFileTips) {
                        textInput.value = '';
                    }
                }
                $api.msg('附件删除成功');
            }
        },
    });
};

const scrollToBottom = throttle(function () {
    nextTick(() => {
        try {
            let query;
            // #ifdef MP-WEIXIN
            query = uni.createSelectorQuery().in(instance);
            // #endif
            // #ifndef MP-WEIXIN
            query = uni.createSelectorQuery();
            // #endif
            
            query.select('.scrollView').boundingClientRect();
            query.select('.list-content').boundingClientRect();
            query.exec((res) => {
                if (!res || !res[0] || !res[1]) {
                    console.warn('scrollToBottom: 元素未找到或尚未渲染');
                    return;
                }
                const scrollViewHeight = res[0].height;
                const scrollContentHeight = res[1].height;
                if (scrollContentHeight > scrollViewHeight) {
                    const scrolldistance = scrollContentHeight - scrollViewHeight;
                    scrollTop.value = scrolldistance;
                }
            });
        } catch (err) {
            console.warn(err);
        }
    });
}, 500);

function getGuess() {
    $api.chatRequest('/guest', { sessionId: chatSessionID.value }, 'POST').then((res) => {
        console.log('getGuess ---- res:', res);
        guessList.value = res.data;
        showGuess.value = true;
        nextTick(() => {
            scrollToBottom();
        });
    }).catch((err) => {
        console.warn('getGuess 请求失败:', err);
    });
}

// 从文件路径提取文件名
function getFileNameFromPath(filePath) {
    if (!filePath) return '';
    // 处理反斜杠和正斜杠
    const path = filePath.replace(/\\/g, '/');
    const lastSlashIndex = path.lastIndexOf('/');
    if (lastSlashIndex !== -1) {
        return path.substring(lastSlashIndex + 1);
    }
    return path;
}

// 从文件名推断文件类型
function getFileTypeFromName(fileName) {
    if (!fileName) return '';
    const lowerName = fileName.toLowerCase();
    if (lowerName.endsWith('.jpg') || lowerName.endsWith('.jpeg')) return 'image/jpeg';
    if (lowerName.endsWith('.png')) return 'image/png';
    if (lowerName.endsWith('.gif')) return 'image/gif';
    if (lowerName.endsWith('.bmp')) return 'image/bmp';
    if (lowerName.endsWith('.webp')) return 'image/webp';
    if (lowerName.endsWith('.svg')) return 'image/svg+xml';
    if (lowerName.endsWith('.pdf')) return 'application/pdf';
    if (lowerName.endsWith('.doc')) return 'application/msword';
    if (lowerName.endsWith('.docx')) return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
    if (lowerName.endsWith('.ppt')) return 'application/vnd.ms-powerpoint';
    if (lowerName.endsWith('.pptx')) return 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
    if (lowerName.endsWith('.xls')) return 'application/vnd.ms-excel';
    if (lowerName.endsWith('.xlsx')) return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
    if (lowerName.endsWith('.txt')) return 'text/plain';
    if (lowerName.endsWith('.md')) return 'text/markdown';
    if (lowerName.endsWith('.html') || lowerName.endsWith('.htm')) return 'text/html';
    if (lowerName.endsWith('.csv')) return 'text/csv';
    return '';
}

function isImage(type, name) {
    if (!type && !name) return false;
    
    const debug = false;
    if (debug) console.log('isImage检查:', { type, name });
    
    if (type) {
        const lowerType = type.toLowerCase();
        
        if (lowerType.includes('image/')) {
            if (debug) console.log('通过MIME类型识别为图片:', lowerType);
            return true;
        }
        
        if (lowerType.includes('image')) {
            if (debug) console.log('通过"image"关键词识别为图片:', lowerType);
            return true;
        }
        
        const imageExtensionsInType = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'heic', 'heif', 'tiff', 'tif'];
        for (const ext of imageExtensionsInType) {
            if (lowerType.includes(ext)) {
                if (debug) console.log('通过类型中的扩展名识别为图片:', ext);
                return true;
            }
        }
    }
    
    if (name) {
        const lowerName = name.toLowerCase();
        const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg', '.heic', '.heif', '.tiff', '.tif', '.jfif', '.pjpeg', '.pjp'];
        for (const ext of imageExtensions) {
            if (lowerName.endsWith(ext)) {
                if (debug) console.log('通过文件扩展名识别为图片:', ext);
                return true;
            }
        }
        
        const imageExtensionsWithoutDot = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg', 'heic', 'heif', 'tiff', 'tif', 'jfif', 'pjpeg', 'pjp'];
        for (const ext of imageExtensionsWithoutDot) {
            if (lowerName.endsWith('.' + ext)) {
                if (debug) console.log('通过带点的扩展名识别为图片:', ext);
                return true;
            }
        }
        
        if (debug) console.log('未识别为图片:', lowerName);
    }
    
    if (debug) console.log('不是图片文件');
    return false;
}

function isFile(type) {
    const allowedTypes = config.allowedFileTypes || [];
    if (!allowedTypes.includes(type)) {
        return false;
    }
    return true;
}

function jumpUrl(file) {
    if (!file.url && !file.tempPath) {
        $api.msg('文件地址丢失');
        return;
    }
    
    if (isImage(file.type, file.name)) {
        const imageUrl = file.tempPath || file.url;
        uni.previewImage({ urls: [imageUrl], current: 0 });
    } else {
        window.open(file.url);
    }
}

function VerifyNumberFiles(additionalCount = 1) {
    const currentCount = filesList.value.length;
    const maxCount = config.allowedFileNumber || 9;
    
    if (currentCount + additionalCount > maxCount) {
        $api.msg(`最多只能上传${maxCount}个文件，当前已有${currentCount}个`);
        return true;
    } else {
        return false;
    }
}

function onImageLoad(file) {
    const index = filesList.value.findIndex(f => f.url === file.url);
    if (index !== -1) {
        filesList.value[index].loading = false;
        filesList.value[index].error = false;
    }
}

function onImageError(file) {
    const index = filesList.value.findIndex(f => f.url === file.url);
    if (index !== -1) {
        filesList.value[index].loading = false;
        filesList.value[index].error = true;
    }
}

function retryImageLoad(file) {
    const index = filesList.value.findIndex(f => f.url === file.url);
    if (index !== -1) {
        filesList.value[index].loading = true;
        filesList.value[index].error = false;
        // 触发重新加载
        setTimeout(() => {
            if (filesList.value[index]) {
                filesList.value[index].loading = false;
            }
        }, 100);
    }
}

function uploadCamera(type = 'camera') {
    // 在微信小程序中检查权限
    // #ifdef MP-WEIXIN
    const scope = type === 'camera' ? 'scope.camera' : 'scope.writePhotosAlbum';
    
    uni.getSetting({
        success: (res) => {
            if (!res.authSetting[scope]) {
                // 未授权，发起授权请求
                uni.authorize({
                    scope: scope,
                    success: () => {
                        // 授权成功，执行选择图片
                        chooseImageAfterAuth();
                    },
                    fail: (err) => {
                        console.error('授权失败:', err);
                        if (err.errMsg && err.errMsg.includes('auth deny')) {
                            uni.showModal({
                                title: '权限提示',
                                content: `需要${type === 'camera' ? '相机' : '相册'}权限才能上传图片，请在设置中开启权限`,
                                showCancel: false,
                                confirmText: '确定'
                            });
                        } else {
                            $api.msg('授权失败，请重试');
                        }
                    }
                });
            } else {
                // 已授权，直接执行选择图片
                chooseImageAfterAuth();
            }
        },
        fail: (err) => {
            console.error('获取设置失败:', err);
            chooseImageAfterAuth(); // 失败时也尝试选择图片
        }
    });
    // #endif
    
    // #ifndef MP-WEIXIN
    // 非微信小程序环境直接选择图片
    chooseImageAfterAuth();
    // #endif
    
    function chooseImageAfterAuth() {
        uni.chooseImage({
            count: 9, //支持多选，最多9张
            sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图，默认二者都有
            // sourceType: [type], // 移除 sourceType 参数，解决微信 "unknown scene" 错误
            success: function (res) {
                const tempFilePaths = res.tempFilePaths;
                const files = res.tempFiles;
                
                // 检查文件数量限制
                if (VerifyNumberFiles(files.length)) return;
                
                // 显示上传提示
                $api.msg(`开始上传${files.length}张图片...`);
                
                // 上传所有图片
                const uploadPromises = tempFilePaths.map((filePath, index) => {
                    return $api.uploadFile(filePath, true).then((resData) => {
                        resData = JSON.parse(resData);
                        if (resData.code === 200 && resData.filePath) {
                            // 从文件对象获取文件信息
                            const fileInfo = files[index] || {};
                            const fileName = getFileNameFromPath(fileInfo.name || filePath);
                            const fileType = fileInfo.type || getFileTypeFromName(fileName);
                            const fileSize = fileInfo.size || 0;
                            
                            // 使用统一的文件路径处理函数
                            const processedFile = processFilePath(
                                resData.filePath, // 原始服务器路径
                                fileName,
                                fileType,
                                fileSize,
                                tempFilePaths[index] // 临时路径用于预览
                            );
                            
                            // 添加图片加载状态字段
                            processedFile.loading = false;
                            processedFile.error = false;
                            
                            return processedFile;
                        } else {
                            throw new Error(resData.msg || '上传失败');
                        }
                    });
                });
                
                Promise.all(uploadPromises).then((uploadedFiles) => {
                    // 将所有上传成功的文件添加到filesList，并设置图片加载状态
                    uploadedFiles.forEach(file => {
                        if (isImage(file.type, file.name)) {
                            file.loading = true; // 图片开始加载
                        }
                        filesList.value.push(file);
                    });
                    textInput.value = state.uploadFileTips;
                    showfile.value = false; // 关闭上传面板
                    $api.msg(`成功上传${uploadedFiles.length}张图片`);
                }).catch((error) => {
                    $api.msg(error.message || '图片上传失败');
                });
            },
            fail: function (err) {
                console.error('选择图片失败:', err);
                // 专门处理微信 "unknown scene" 错误
                if (err.errMsg && err.errMsg.includes('unknown scene')) {
                    $api.msg('选择图片失败，请尝试重新选择或检查权限设置');
                } else if (err.errMsg && err.errMsg.includes('auth deny')) {
                    $api.msg('没有相机或相册权限，请在设置中开启');
                } else {
                    $api.msg('选择图片失败: ' + (err.errMsg || '未知错误'));
                }
            }
        });
    }
}

function getUploadFile(type = 'camera') {
    // 检测是否是微信小程序环境
    const isWeixinMiniProgram = typeof wx !== 'undefined' && wx.chooseMessageFile;
    
    console.log('当前环境检测:', {
        isWeixinMiniProgram,
        wxExists: typeof wx !== 'undefined',
        hasChooseMessageFile: typeof wx !== 'undefined' && wx.chooseMessageFile
    });
    
    if (isWeixinMiniProgram) {
        console.log('微信小程序环境，使用uni.chooseMessageFile');
        // 微信小程序环境：使用uni.chooseMessageFile
        uni.chooseMessageFile({
            count: 9,
            type: 'file',
            success: (res) => {
                console.log('uni.chooseMessageFile返回的res:', res);
                // uni.chooseMessageFile返回的数据结构不同
                // tempFiles数组中每个对象有path、name、size等属性
                const tempFiles = res.tempFiles || [];
                const tempFilePaths = tempFiles.map(file => file.path);
                const files = tempFiles;
                
                console.log('tempFilePaths:', tempFilePaths);
                console.log('tempFiles:', tempFiles);
                if (files && files.length > 0) {
                    console.log('第一个文件详情:', files[0]);
                    console.log('第一个文件的所有属性:', Object.keys(files[0]));
                    // 详细记录每个文件的所有属性
                    files.forEach((file, index) => {
                        console.log(`文件 ${index} 完整对象:`, JSON.stringify(file));
                        console.log(`文件 ${index} 关键属性:`, {
                            name: file.name,
                            type: file.type,
                            path: file.path,
                            size: file.size,
                            hasType: 'type' in file,
                            typeIsString: typeof file.type === 'string',
                            typeLength: file.type ? file.type.length : 0
                        });
                    });
                }
                
                // 调用公共的文件处理函数
                handleSelectedFiles(tempFilePaths, files);
            },
            fail: (err) => {
                console.error('uni.chooseMessageFile失败:', err);
                // 微信小程序特定的错误处理
                if (err.errMsg && err.errMsg.includes('cancel')) {
                    // 用户取消选择，不提示错误
                    console.log('用户取消选择文件');
                } else {
                    $api.msg('选择文件失败，请重试');
                }
            }
        });
    } else {
        console.log('非微信小程序环境，使用uni.chooseFile');
        // 其他平台：使用uni.chooseFile
        uni.chooseFile({
            count: 9,
            success: (res) => {
                console.log('uni.chooseFile返回的res:', res);
                const tempFilePaths = res.tempFilePaths;
                const files = res.tempFiles;
                
                console.log('tempFilePaths:', tempFilePaths);
                console.log('tempFiles:', files);
                if (files && files.length > 0) {
                    console.log('第一个文件详情:', files[0]);
                    console.log('第一个文件的所有属性:', Object.keys(files[0]));
                    // 详细记录每个文件的所有属性
                    files.forEach((file, index) => {
                        console.log(`文件 ${index} 完整对象:`, JSON.stringify(file));
                        console.log(`文件 ${index} 关键属性:`, {
                            name: file.name,
                            type: file.type,
                            path: file.path,
                            size: file.size,
                            hasType: 'type' in file,
                            typeIsString: typeof file.type === 'string',
                            typeLength: file.type ? file.type.length : 0
                        });
                    });
                }
                
                // 调用公共的文件处理函数
                handleSelectedFiles(tempFilePaths, files);
            },
            fail: (err) => {
                console.error('uni.chooseFile失败:', err);
                if (err.errMsg && !err.errMsg.includes('cancel')) {
                    $api.msg('选择文件失败，请重试');
                }
            }
        });
    }
}

// 处理服务器返回的文件路径，生成正确的显示URL和服务器路径
function processFilePath(originalFilePath, fileName, fileType, fileSize, tempPath) {
    let displayUrl = originalFilePath; // 用于缩略图显示的URL（外网域名）
    const serverPath = originalFilePath; // 原始服务器路径（内网地址，用于对话接口）
    
    console.log('processFilePath原始fileUrl:', originalFilePath);
    
    // 如果filePath包含IP地址，替换为配置的域名（用于显示）
    if (displayUrl && displayUrl.includes('://')) {
        // 检查是否是本地临时路径（如http://tmp/），如果是则保持原样
        if (displayUrl.startsWith('http://tmp/')) {
            // 本地临时路径，保持原样
            console.log('本地临时路径，保持原样:', displayUrl);
        } else {
            // 方法1：直接替换域名部分（保持路径结构）- 使用兼容的方法
            // 例如：http://10.98.80.146/file/xxx.jpg -> https://www.xjksly.cn/file/xxx.jpg
            const originalUrl = displayUrl;
            
            // 提取协议、域名和路径部分
            let protocol = '';
            let domain = '';
            let path = '';
            
            // 分离协议和剩余部分
            const protocolIndex = originalUrl.indexOf('://');
            if (protocolIndex !== -1) {
                protocol = originalUrl.substring(0, protocolIndex + 3);
                const rest = originalUrl.substring(protocolIndex + 3);
                const slashIndex = rest.indexOf('/');
                if (slashIndex !== -1) {
                    domain = rest.substring(0, slashIndex);
                    path = rest.substring(slashIndex);
                } else {
                    domain = rest;
                    path = '/';
                }
            }
            
            console.log('解析结果:', { protocol, domain, path });
            
            // 使用config.baseUrl或config.imgBaseUrl作为新域名
            let baseUrl = config.baseUrl || config.imgBaseUrl;
            // 如果baseUrl以/api/ks结尾，去掉这个部分
            if (baseUrl.endsWith('/api/ks')) {
                baseUrl = baseUrl.substring(0, baseUrl.length - 7);
            }
            
            // 构建新URL：使用新域名 + 原路径
            // 确保baseUrl不以/结尾，path以/开头
            let cleanBaseUrl = baseUrl;
            if (cleanBaseUrl.endsWith('/')) {
                cleanBaseUrl = cleanBaseUrl.substring(0, cleanBaseUrl.length - 1);
            }
            if (!path.startsWith('/')) {
                path = '/' + path;
            }
            
            displayUrl = cleanBaseUrl + path;
            console.log('替换域名后的displayUrl（用于显示）:', displayUrl);
        }
    } else if (displayUrl && !displayUrl.startsWith('http')) {
        // 如果filePath不是完整的URL，直接添加图片基础URL前缀
        displayUrl = config.imgBaseUrl + displayUrl;
        console.log('非完整URL，添加imgBaseUrl前缀:', displayUrl);
    }
    
    return {
        url: displayUrl, // 使用处理后的完整URL（用于缩略图显示）
        serverPath: serverPath, // 原始服务器路径（内网地址，用于对话接口）
        type: fileType,
        name: fileName,
        size: fileSize > 0 ? $api.formatFileSize(fileSize) : '',
        tempPath: tempPath // 保存临时路径用于预览
    };
}

// 处理选择的文件（公共逻辑）
function handleSelectedFiles(tempFilePaths, files) {
    // 检查文件数量限制
    if (VerifyNumberFiles(files.length)) return;
    
    const allowedTypes = config.allowedFileTypes || [];
    
    // 调试：在文件类型检查之前记录详细信息
    console.log('=== handleSelectedFiles 文件类型检查开始 ===');
    console.log('allowedTypes配置:', allowedTypes);
    console.log('files数组长度:', files.length);
    files.forEach((file, index) => {
        console.log(`文件 ${index} 检查前详情:`, {
            name: file.name,
            type: file.type,
            hasType: 'type' in file,
            typeValue: file.type,
            typeIsString: typeof file.type === 'string',
            typeLength: file.type ? file.type.length : 0,
            size: file.size,
            path: file.path
        });
        // 尝试从文件名推断类型
        const inferredType = getFileTypeFromName(file.name);
        console.log(`文件 ${index} 从文件名推断的类型:`, inferredType);
        // 检查是否在allowedTypes中
        const isAllowedByType = allowedTypes.includes(file.type);
        const isAllowedByInferred = allowedTypes.includes(inferredType);
        const isImageFile = isImage(file.type, file.name);
        console.log(`文件 ${index} 检查结果:`, {
            isAllowedByType,
            isAllowedByInferred,
            isImageFile,
            finalAllowed: isAllowedByType || isAllowedByInferred || isImageFile
        });
    });
    console.log('=== handleSelectedFiles 文件类型检查结束 ===');
    
    // 检查所有文件类型 - 增强版：优先使用file.type，回退到文件名推断
    const invalidFiles = files.filter(file => {
        // 如果文件类型存在且在允许的类型列表中，则通过
        if (file.type && allowedTypes.includes(file.type)) {
            return false;
        }
        
        // 尝试从文件名推断类型
        const inferredType = getFileTypeFromName(file.name);
        if (inferredType && allowedTypes.includes(inferredType)) {
            return false;
        }
        
        // 如果是图片，也通过
        if (isImage(file.type, file.name)) {
            return false;
        }
        
        // 否则，文件无效
        return true;
    });
    
    if (invalidFiles.length > 0) {
        // 调试：查看不支持的文件类型
        console.log('不支持的文件类型:', invalidFiles.map(f => ({name: f.name, type: f.type})));
        // 更详细地显示为什么这些文件不被支持
        invalidFiles.forEach((file, index) => {
            const inferredType = getFileTypeFromName(file.name);
            console.log(`无效文件 ${index} 分析:`, {
                name: file.name,
                type: file.type,
                inferredType,
                isImage: isImage(file.type, file.name),
                isInAllowedTypes: allowedTypes.includes(file.type),
                isInferredInAllowedTypes: allowedTypes.includes(inferredType)
            });
        });
        return $api.msg('仅支持 txt md html word doc docx pdf ppt pptx csv excel xlsx 和图片格式');
    }
    
    // 显示上传提示
    const imageCount = files.filter(file => isImage(file.type, file.name)).length;
    const otherFileCount = files.length - imageCount;
    let tip = '开始上传';
    if (imageCount > 0) tip += `${imageCount}张图片`;
    if (otherFileCount > 0) {
        if (imageCount > 0) tip += '和';
        tip += `${otherFileCount}个文件`;
    }
    $api.msg(tip + '...');
    
    // 上传所有文件
    const uploadPromises = tempFilePaths.map((filePath, index) => {
        return $api.uploadFile(filePath, true).then((resData) => {
            resData = JSON.parse(resData);
            console.log('服务器返回的resData:', resData);
            if (resData.code === 200 && resData.filePath) {
                // 从文件对象或文件路径获取文件信息
                const fileInfo = files[index] || {};
                const fileName = fileInfo.name || getFileNameFromPath(tempFilePaths[index]);
                const fileType = fileInfo.type || getFileTypeFromName(fileName);
                const fileSize = fileInfo.size || 0;
                
                // 使用统一的文件路径处理函数
                const processedFile = processFilePath(
                    resData.filePath, // 原始服务器路径
                    fileName,
                    fileType,
                    fileSize,
                    tempFilePaths[index] // 临时路径用于预览
                );
                
                // 调试：记录文件信息
                console.log('上传文件信息:', {
                    fileInfo: fileInfo,
                    type: fileType,
                    name: fileName,
                    size: fileSize,
                    isImage: isImage(fileType, fileName),
                    originalFilePath: resData.filePath,
                    displayUrl: processedFile.url,
                    serverPath: processedFile.serverPath,
                    imgBaseUrl: config.imgBaseUrl
                });
                
                return processedFile;
            } else {
                throw new Error(resData.msg || '上传失败');
            }
        });
    });
    
    Promise.all(uploadPromises).then((uploadedFiles) => {
        // 将所有上传成功的文件添加到filesList
        uploadedFiles.forEach(file => {
            if (isImage(file.type, file.name)) {
                file.loading = true; // 图片开始加载
                file.error = false;
            }
            filesList.value.push(file);
        });
        textInput.value = state.uploadFileTips;
        showfile.value = false; // 关闭上传面板
        $api.msg(`成功上传${uploadedFiles.length}个文件`);
    }).catch((error) => {
        $api.msg(error.message || '文件上传失败');
    });
}

const tipsPermisson = () => {
    uni.showToast({
        title: '需要授权麦克风权限才能使用语音功能',
        icon: 'none',
    });
};

const handleTouchStart = async (e) => {
    if (!isAudioPermission.value) {
        return tipsPermisson();
    }
    cancelAudio();
    startY.value = e.touches[0].clientY;
    status.value = 'recording';
    showfile.value = false;
    startRecording();
    $api.sleep(1000).then(() => {
        scrollToBottom();
    });
};

const handleTouchMove = (e) => {
    const moveY = e.touches[0].clientY;
    if (startY.value - moveY > cancelThreshold) {
        status.value = 'cancel';
    } else {
        status.value = 'recording';
    }
};

const handleTouchEnd = () => {
    if (status.value === 'cancel') {
        console.log('取消发送');
        cancelRecording();
        status.value = 'idle';
    } else {
        stopRecording();
        if (isAudioPermission.value) {
            // 主要根据录音时长判断，而不是完全依赖识别结果
            // 由于setInterval是异步的，这里需要考虑计时延迟
            const actualDuration = recordingDuration.value > 0 ? recordingDuration.value : (isRecording.value ? 0.5 : 0);
            if (actualDuration < 1) {
                $api.msg('说话时长太短');
                status.value = 'idle';
            } else {
                // 状态管理由useAudioRecorder hook内部处理
                status.value = 'idle';
            }
        }
    }
};

const handleTouchCancel = () => {
    stopRecording();
    status.value = 'idle';
};

function closeGuess() {
    showGuess.value = false;
}

function changeVoice() {
    isVoice.value = !isVoice.value;
}

function changeShowFile() {
    showfile.value = !showfile.value;
}

function closeFile() {
    showfile.value = false;
}

function copyMarkdown(value) {
    $api.copyText(value);
}

function userGoodFeedback(msg) {
    // $api.msg('该功能正在开发中，敬请期待后续更新！');
    feeback.value?.open();
    feebackData.value = msg;
}

function confirmFeeBack(value) {
    useChatGroupDBStore()
        .badFeedback(feebackData.value, value)
        .then(() => {
            feeback.value?.close();
            feeBackTips.value?.open();
        });
}

// 防抖定时器
let ttsDebounceTimer = null;

// 保存上一次调用的文本内容，避免重复调用TTS
let lastSpeechText = '';

function readMarkdown(value, index, options = {}) {
    console.log('🎤 readMarkdown called');
    console.log('📝 Text to speak:', value ? value.substring(0, 100) + '...' : 'No text');
    console.log('🔢 Index:', index);
    console.log('🔢 Current speechIndex:', speechIndex.value);
    console.log('⏸️ Is paused:', isPaused.value);
    console.log('🔊 Is speaking:', isSpeaking.value);
    
    // 清除之前的防抖定时器
    if (ttsDebounceTimer) {
        clearTimeout(ttsDebounceTimer);
    }
    
    // 总是先停止当前播放，无论是不是同一消息
    console.log('🛑 Always stopping current speech before starting new one');
    speechIndex.value = index;
    
    // 立即调用speak，不使用防抖延迟
    const speakNow = () => {
        // 检查文本内容是否发生变化，避免重复调用TTS
        if (value !== lastSpeechText) {
            console.log('🎵 Starting new speech');
            console.log('🎵 Calling speak function with text length:', value ? value.length : 0);
            try {
                speak(value);
                console.log('✅ Speak function called successfully');
                // 更新上一次调用的文本内容
                lastSpeechText = value;
            } catch (error) {
                console.error('❌ Error calling speak function:', error);
            }
        } else {
            console.log('🔄 Same text as last speech, skipping duplicate TTS call');
        }
    };
    
    // 改进防抖逻辑，确保在短时间内只调用一次
    if (options.immediate) {
        // 如果是onComplete回调，立即播放
        speakNow();
    } else {
        // 对于流式数据，总是使用防抖，避免频繁调用
        ttsDebounceTimer = setTimeout(speakNow, 500); // 延长防抖时间到500ms
    }
}
function stopMarkdown(value, index) {
    console.log('⏸️ stopMarkdown called for index:', index);
    console.log('🔢 Current speechIndex:', speechIndex.value);
    console.log('🔊 Is speaking:', isSpeaking.value);
    console.log('⏸️ Is paused:', isPaused.value);
    
    // 清除防抖定时器
    if (ttsDebounceTimer) {
        clearTimeout(ttsDebounceTimer);
        ttsDebounceTimer = null;
    }
    
    speechIndex.value = index;
    pause();
}
function refreshMarkdown(index) {
    if (isTyping.value) {
        $api.msg('正在生成');
    } else {
        const text = messages.value[index - 1].text;
        sendMessageGuess(text);
    }
}

const jobSearchQueries = [
    '喀什地区有哪些薪资 12K 以上的岗位适合我？',
    '喀什地区 3 年工作经验能找到哪些 12K 以上的工作？',
    '喀什地区哪些公司在招聘，薪资范围在 12K 以上？',
    '喀什地区有哪些企业提供 15K 以上的岗位？',
    '喀什地区哪些公司在招 3-5 年经验的岗位？',
    '我有三年的工作经验，能否推荐一些适合我的喀什地区的国企 岗位？',
    '喀什地区国企目前在招聘哪些岗位？',
    '喀什地区有哪些适合 3 年经验的国企岗位？',
    '喀什地区国企招聘的岗位待遇如何？',
    '喀什地区国企岗位的薪资水平是多少？',
    '喀什地区哪些国企支持双休 & 五险一金完善？',
    '喀什地区有哪些公司支持远程办公？',
    '喀什地区有哪些外企的岗位，薪资 12K 以上的多吗？',
    '喀什地区哪些企业在招聘 Web3.0 相关岗位？',
    '喀什地区哪些岗位支持海外远程？薪资如何？',
    '喀什地区招聘 AI/大数据相关岗位的公司有哪些？',
];

function changeQueries(value) {
    queries.value = getRandomJobQueries(jobSearchQueries);
}

function getRandomJobQueries(queries, count = 2) {
    const shuffled = queries.sort(() => 0.5 - Math.random()); // 随机打乱数组
    return shuffled.slice(0, count); // 取前 count 条
}

// 切换tab
function switchTab(tab) {
    activeTab.value = tab;
}

// 检查消息是否应该显示在当前tab
function shouldShowMessage(msg) {
    if (msg.self) {
        return true; // 用户自己的消息总是显示
    }
    
    if (activeTab.value === 'policy') {
        // 政策查询tab：显示除了岗位卡片以外的所有内容
        // 岗位卡片通常包含特定的标记，如```job-json或岗位推荐等关键词
        const isJobCard = msg.displayText && (
            msg.displayText.includes('```job-json') ||
            msg.displayText.includes('岗位推荐') ||
            msg.displayText.includes('推荐岗位') ||
            msg.displayText.includes('岗位信息') ||
            (msg.displayText.includes('```') && msg.displayText.includes('公司') && msg.displayText.includes('薪资'))
        );
        return !isJobCard;
    } else {
        // 岗位推荐tab：只显示岗位卡片内容
        const isJobCard = msg.displayText && (
            msg.displayText.includes('```job-json') ||
            msg.displayText.includes('岗位推荐') ||
            msg.displayText.includes('推荐岗位') ||
            msg.displayText.includes('岗位信息') ||
            (msg.displayText.includes('```') && msg.displayText.includes('公司') && msg.displayText.includes('薪资'))
        );
        return isJobCard;
    }
}

// 长按事件处理函数
function handleLongPress(msg, index) {
    isSelectMode.value = true;
    selectedMessages.value = [index];
    
    // 如果长按的是用户消息，同时选中对应的AI回复
    if (msg.self) {
        const nextIndex = index + 1;
        if (nextIndex < messages.value.length && !messages.value[nextIndex].self) {
            selectedMessages.value.push(nextIndex);
        }
    }
}

// 选择/取消选择消息
function toggleSelectMessage(index) {
    const msg = messages.value[index];
    const idx = selectedMessages.value.indexOf(index);
    
    if (idx > -1) {
        // 取消选择
        selectedMessages.value.splice(idx, 1);
        
        // 如果取消选择的是用户消息，同时取消选择对应的AI回复
        if (msg.self) {
            const nextIndex = index + 1;
            if (nextIndex < messages.value.length && !messages.value[nextIndex].self) {
                const aiIdx = selectedMessages.value.indexOf(nextIndex);
                if (aiIdx > -1) {
                    selectedMessages.value.splice(aiIdx, 1);
                }
            }
        }
        
        if (selectedMessages.value.length === 0) {
            isSelectMode.value = false;
        }
    } else {
        // 选择消息
        selectedMessages.value.push(index);
        
        // 如果选择的是用户消息，同时选择对应的AI回复
        if (msg.self) {
            const nextIndex = index + 1;
            if (nextIndex < messages.value.length && !messages.value[nextIndex].self) {
                if (!selectedMessages.value.includes(nextIndex)) {
                    selectedMessages.value.push(nextIndex);
                }
            }
        }
    }
}

// 退出选择模式
function exitSelectMode() {
    isSelectMode.value = false;
    selectedMessages.value = [];
}

// 全选消息
function selectAllMessages() {
    selectedMessages.value = messages.value.map((_, index) => index);
}

// 删除选中消息
function deleteSelectedMessages() {
    if (selectedMessages.value.length === 0) return;
    
    uni.showModal({
        content: `确定删除${selectedMessages.value.length}条消息吗？`,
        success(res) {
            if (res.confirm) {
                // 调用store中的删除方法
                useChatGroupDBStore().deleteMessages(selectedMessages.value);
                // 退出选择模式
                exitSelectMode();
                $api.msg('消息删除成功');
            }
        }
    });
}

defineExpose({ scrollToBottom, closeGuess, closeFile, changeQueries, handleTouchCancel, switchTab });
</script>

<style lang="stylus" scoped>
/* 过渡样式 */
.collapse-enter-active,
.collapse-leave-active {
  transition: max-height 0.3s ease, opacity 0.3s ease;
}

.collapse-enter-from,
.collapse-leave-to {
  max-height: 0;
  opacity: 0;
}

.collapse-enter-to,
.collapse-leave-from {
  max-height: 400rpx; /* 根据你内容最大高度设定 */
  opacity: 1;
}
.msg-filecontent
    display: flex
    flex-wrap: wrap
.msg-files
    overflow: hidden
    margin-right: 10rpx
    height: 30rpx
    max-width: 201rpx
    background: #FFFFFF
    border-radius: 10rpx
    display: flex
    align-items: center
    justify-content: flex-start
    padding: 10rpx
    color: #000000
    margin-bottom: 10rpx
    .msg-file-icon
        width: 29rpx
        height: 26rpx
        padding-right: 10rpx
    .msg-file-text
        flex: 1
        white-space: nowrap
        overflow: hidden
        text-overflow: ellipsis
        color: rgba(96, 96, 96, 1)
        font-size: 24rpx
.msg-files:active
    background: #e9e9e9

// 消息中的图片文件样式
.msg-image-file
    height: 120rpx
    width: 120rpx
    padding: 4rpx
    flex-direction: column
    justify-content: center
    .msg-image-thumbnail
        width: 100%
        height: 80rpx
        border-radius: 8rpx
        margin-bottom: 8rpx
    .msg-file-text
        font-size: 20rpx
        text-align: center
        white-space: nowrap
        overflow: hidden
        text-overflow: ellipsis
.guess
    padding: 5rpx 0 10rpx 0
    .guess-list
        padding: 16rpx 24rpx
        margin-top: 28rpx
        font-size: 24rpx
        color: #8c8c8c
        width: 100%;
        border-radius: 20rpx 20rpx 20rpx 20rpx;
        border: 2rpx solid #E5E5E5;
        font-size: 28rpx;
        color: #333333;
        line-height: 33rpx;
    .gulist
        display: flex
        flex-wrap: wrap
        position: relative
image-margin-top = 40rpx
.chat-container
    display: flex;
    flex-direction: column;
    height: 100%;
    position: relative
    z-index: 1
    background: #FFFFFF

.chat-background
    position: absolute
    padding: 44rpx;
    display: flex
    flex-direction: column
    justify-content: flex-start
    align-items: center
    width: calc(100% - 88rpx)
    position: relative
    z-index: 1
    .backlogo
        width: 313rpx;
        height: 190rpx;
    .back-rowTitle
        height: 56rpx;
        font-weight: bold;
        font-size: 40rpx;
        color: #333333;
        line-height: 47rpx;
        margin-top: 40rpx
    .back-rowText
        margin-top: 28rpx
        width: 100%;
        height: 148rpx;
        font-weight: 400;
        font-size: 28rpx;
        color: #333333;
        line-height: 40rpx
        // border-bottom: 2rpx dashed rgba(0, 0, 0, 0.2);
        border-bottom: 2rpx solid transparent;
        background-image: linear-gradient(to right, rgba(0, 0, 0, 0.2) 50%, transparent 50%);
        background-size: 10rpx 2rpx; /* 调整虚线宽度和间距 */
        background-repeat: repeat-x;
        background-position: 0 148rpx
    .back-rowh3
        width: 100%;
        font-weight: 500;
        font-size: 28rpx;
        color: #000000;
        margin-top: 28rpx
    .back-rowmsg
        width: calc(100% - 32rpx)
        margin-top: 24rpx
        font-weight: 500;
        color: rgba(51, 51, 51, 1);
        line-height: 28rpx;
        font-size: 24rpx
        background: rgba(246, 246, 246, 1);
        border-radius: 8rpx 8rpx 8rpx 8rpx;
        padding: 32rpx 18rpx;

.chat-list {
    flex: 1;
    overflow-y: auto;
    white-space: pre-wrap;
}
.list-content {
    padding: 0 44rpx 10rpx 44rpx;
}
.chat-item {
    display: flex;
    align-items: flex-start;
    margin-bottom: 10rpx;
    width: 100%;
}
.chat-item.self {
    justify-content: flex-end;
}
.message
    margin-top: 0rpx
    // max-width: 80%;
    width: 100%;
    word-break: break-word;
    color: #333333;
    user-select: text;
    -webkit-user-select: text;
    .message-markdown
        border-radius: 0 20rpx 20rpx 20rpx;
        padding: 20rpx 20rpx 20rpx 20rpx;
        background: #F6F6F6;
        .message-controll
            display: flex
            justify-content: space-between
            align-items: center
            border-top: 2rpx solid #EAEAEA
            padding: 24rpx 0 4rpx 0
            margin-top: 10rpx
            .controll-left
            .controll-right
                .controll-icon
                    width: 60rpx;
                    height: 60rpx;

.messageNull
    display: none
.msg-loading{
    background: #F6F6F6;
    border-radius: 20rpx 0 20rpx 20rpx;
    padding: 20rpx;
    width: fit-content;
    display: flex;
    align-items: center;
    justify-content: center;
    
    .loading-content{
        display: flex;
        align-items: center;
        justify-content: center;
        gap: 16rpx;
    }
    
    .loading-text{
        font-size: 28rpx;
        color: #666666;
        font-weight: 500;
    }
}
.loaded{
    padding-left: 20rpx
}
.chat-item.self .message {
    background: linear-gradient( 225deg, #DAE2FE 0%, #E9E3FF 100%);
        border-radius: 20rpx 0 20rpx 20rpx;
    padding: 20rpx;
    width: fit-content;
}
.input-area {
    padding: 32rpx 28rpx 24rpx 28rpx;
    /* #ifdef H5 */
    padding-bottom: calc(24rpx + env(safe-area-inset-bottom) + 70rpx);
    /* #endif */
    /* #ifdef MP-WEIXIN */
    /* 小程序不支持CSS中的本地图片，使用image标签替代 */
    padding-bottom: calc(24rpx + env(safe-area-inset-bottom) + 40rpx - 50rpx);
    /* #endif */
    position: relative;
    background: #FFFFFF;
    box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(11,44,112,0.06);
    transition: height 2s ease-in-out;
    z-index: 1001;
}
.ai-tips{
    font-size: 24rpx;
    color: #8c8c8c;
    line-height: 33rpx;
    margin-top: 18rpx;
    text-align: center;
}
.input-area::after
    position: absolute
    content: ''
    top: 0
    left: 0
    width: 100%
    z-index: 1
    box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(11,44,112,0.06);
.areatext{
    display: flex;
}
.input {
    flex: 1;
    border-radius: 5rpx;
    min-height: 63rpx;
    line-height: 63rpx;
    padding: 4rpx 24rpx;
    position: relative
    background: #F5F5F5;
    border-radius: 60rpx 60rpx 60rpx 60rpx;
}
.input_vio
    flex: 1;
    border-radius: 5rpx;
    min-height: 63rpx;
    line-height: 63rpx;
    padding: 4rpx 24rpx;
    // position: relative
    border-radius: 60rpx 60rpx 60rpx 60rpx;
    font-size: 28rpx
    color: #333333
    background: #F5F5F5;
    text-align: center
    font-size: 28rpx
    font-weight: 500
    user-select:none;
    -webkit-touch-callout:none;
    -webkit-user-select:none;
    -khtml-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    touch-action: none; /* 禁用默认滚动 */
.input_vio:active
    background: #e8e8e8
.vio_container
    background: transparent
    padding: 28rpx
    text-align: center
    -webkit-touch-callout:none;
    -webkit-user-select:none;
    -khtml-user-select:none;
    -moz-user-select:none;
    -ms-user-select:none;
    touch-action: none; /* 禁用默认滚动 */
    position: fixed;
    left: 0;
    right: 0;
    bottom: 160rpx; /* 为底部导航栏留出空间 */
    z-index: 9999; /* 确保高于其他元素 */
    .record-tip
        font-weight: 400;
        color: #909090;
        text-align: center;
        padding-bottom: 16rpx


.inputplaceholder {
    font-weight: 500;
    font-size: 24rpx;
    color: #000000;
    line-height: 28rpx;
    opacity: 0.4
}
.btn-box
    margin-left: 12rpx;
    width: 70rpx;
    height: 70rpx;
    border-radius: 50%
    background: #F5F5F5;
    display: flex
    align-items: center
    justify-content: center
    .send-btn,
    .receive-btn
        transition: transform 0.5s ease;
        width: 38rpx;
        height: 38rpx;
    .btn-box-round
        width: 22rpx
        height: 22rpx
        border-radius: 4rpx
        background: #FFFFFF
.purple
    background: linear-gradient( 225deg, #9E74FD 0%, #256BFA 100%);
.add-file-btn{
    transform: rotate(45deg)
    transition: transform 0.5s ease;
}
.area-tips{
    font-weight: 400;
    font-size: 26rpx;
    color: #434343;
    margin-top: 18rpx
}

/* 文件上传弹窗 - 向上展开，避免被tabbar遮挡 */
.file-upload-popup {
    position: absolute;
    bottom: 100%;
    left: 0;
    right: 0;
    background: #FFFFFF;
    padding: 0 28rpx 24rpx 28rpx;
    box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(11,44,112,0.06);
    transform: translateY(20rpx);
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
    z-index: 1002;
}

.file-upload-popup.show {
    transform: translateY(0);
    opacity: 1;
    visibility: visible;
}

.area-file
    display: grid
    width: 100%
    grid-template-columns: repeat(3, 1fr)
    grid-gap: 20rpx
    padding: 20rpx 0 0 0;
    .file-card
        display: flex
        flex-direction: column
        align-items: center
        padding: 24rpx 0
        background: #F5F5F5;
        border-radius: 20rpx 20rpx 20rpx 20rpx;
        text
            font-size: 24rpx
            font-weight: 500
            color: rgba(0,0,0,.5)
            padding-top: 8rpx
        .card-img
            height: 56rpx
            width: 56rpx
    .file-card:active
        background: #e8e8e8

.area-uploadfiles
    position: absolute
    bottom: 100%
    width: calc(100% - 30rpx)
    background: #FFFFFF
    left: 0
    padding: 10rpx 0 10rpx 30rpx
    box-shadow: 0rpx -4rpx 10rpx 0rpx rgba(11,44,112,0.06);
    z-index: 1003
    .uploadfiles-scroll
        height: 100%
        .uploadfiles-list
            height: 100%
            display: flex
            margin-right: 28rpx
            flex-wrap: nowrap
            .file-doc
                display: flex
                align-items: center
                justify-content: flex-start
                padding: 16rpx 20rpx 18rpx 20rpx
                height: calc(100% - 40rpx)
                .doc-icon
                    width: 60rpx
                    height: 76rpx
                    margin-right: 20rpx
                .doc-con
                    flex: 1
                    width: 0
            .file-uploadsend
                margin: 10rpx 18rpx 0 0;
                height: 100%
                font-size: 24rpx
                position: relative
                min-width: 200rpx;
                max-width: 200rpx;
                height: 200rpx;
                border-radius: 12rpx;
                border: 2rpx solid #E2E2E2;
                overflow: hidden
                display: flex
                flex-direction: column
                &.file-border
                    border: 2rpx solid #4A90E2;
                    background: #F5F9FF;
                .file-del
                    position: absolute
                    right: 25rpx
                    top: 18rpx
                    z-index: 9
                    border-radius: 50%
                    display: flex
                    align-items: center
                    justify-content: center
                    transform: translate(50%, -10rpx)
                    height: 40rpx
                    width: 37rpx;
                    height: 37rpx;
                    background: #4B4B4B;
                    border: 2rpx solid #FFFFFF;
                .file-del:active
                    background: #e8e8e8
                .filename-text
                    overflow: hidden
                    text-overflow: ellipsis
                    white-space: nowrap
                    color: #333333
                    font-size: 24rpx
                    font-weight: 500
                    max-width: 100%
                .filename-size
                    overflow: hidden
                    text-overflow: ellipsis
                    white-space: nowrap
                    color: #7B7B7B;
                    max-width: 100%
                .file-thumbnail
                    flex: 1
                    display: flex
                    align-items: center
                    justify-content: center
                    overflow: hidden
                    border-radius: 10rpx 10rpx 0 0
                    background: #F8F9FA
                .file-iconImg
                    height: 100%
                    width: 100%
                    object-fit: cover
                .file-info
                    padding: 12rpx 16rpx
                    background: white
                    border-top: 1rpx solid #F0F0F0
                .file-type-tag
                    font-size: 20rpx
                    color: #4A90E2
                    background: #F0F7FF
                    padding: 4rpx 8rpx
                    border-radius: 4rpx
                .image-loading, .image-error
                    position: absolute
                    top: 0
                    left: 0
                    right: 0
                    bottom: 0
                    display: flex
                    flex-direction: column
                    align-items: center
                    justify-content: center
                    background: rgba(255, 255, 255, 0.9)
                .loading-text, .error-text
                    font-size: 24rpx
                    margin-top: 10rpx
                .loading-text
                    color: #999
                .error-text
                    color: #ff4444
                .retry-text
                    font-size: 22rpx
                    color: #4A90E2
                    margin-top: 5rpx
                    text-decoration: underline
                .image-count-badge
                    position: absolute
                    top: 10rpx
                    right: 10rpx
                    background: rgba(0, 0, 0, 0.6)
                    color: white
                    font-size: 20rpx
                    padding: 4rpx 8rpx
                    border-radius: 12rpx
                    z-index: 2
                .filerow
                    display: flex
                    align-items: center
                    margin-top: 7rpx
                    .row-x
                        margin: 0 18rpx
                        height: 20rpx
                        width: 2rpx
                        background: rgba(226, 226, 226, .9)
            .file-border
                width: 160rpx !important;

/* 更美观的loading动画 - 兼容H5和小程序 */
@keyframes ai-loading-dots {
    0%, 20%, 80%, 100% {
        transform: scale(1);
        opacity: 0.6;
    }
    40% {
        transform: scale(1.2);
        opacity: 1;
    }
}

/* 重置默认样式 */
.ai-loading {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8rpx;
    width: auto;
    height: auto;
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0;
    margin: 0;
}

/* 三个点的样式 - 使用标准CSS语法，不使用嵌套 */
.ai-loading view {
    display: inline-block;
    width: 12rpx;
    height: 12rpx;
    border-radius: 50%;
    background-color: #256BFA;
    animation: ai-loading-dots 1.4s ease-in-out infinite both;
    margin: 0;
    padding: 0;
}

/* 为每个点设置不同的动画延迟 */
.ai-loading view:nth-child(1) {
    animation-delay: -0.32s;
}

.ai-loading view:nth-child(2) {
    animation-delay: -0.16s;
}

.ai-loading view:nth-child(3) {
    animation-delay: 0s;
}

/* Tab切换样式 */
.tab-container {
    display: flex;
    background: #FFFFFF;
    border-bottom: 2rpx solid #F4F4F4;
    padding: 0 44rpx;
    height: 88rpx;
    align-items: center;
    z-index: 10;
}

.tab-item {
    flex: 1;
    text-align: center;
    font-size: 28rpx;
    font-weight: 500;
    color: #666666;
    line-height: 88rpx;
    height: 88rpx;
    position: relative;
    transition: all 0.3s ease;
}

.tab-item.active {
    color: #256BFA;
    font-weight: bold;
}

.tab-item.active::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 60rpx;
    height: 4rpx;
    background: #256BFA;
    border-radius: 2rpx;
}

.tab-item:active {
    background-color: #F5F5F5;
}

/* 选择模式样式 */
.select-mode-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 44rpx;
    height: 88rpx;
    background: #FFFFFF;
    border-bottom: 2rpx solid #F4F4F4;
    z-index: 10;
}

.select-header-left {
    display: flex;
    align-items: center;
    gap: 24rpx;
}

.select-count {
    font-size: 28rpx;
    color: #333333;
    font-weight: 500;
}

.select-all {
    font-size: 28rpx;
    color: #256BFA;
    font-weight: 500;
}

.select-header-right {
    display: flex;
    align-items: center;
    gap: 32rpx;
}

.cancel-btn {
    font-size: 28rpx;
    color: #666666;
    font-weight: 500;
}

.delete-btn {
    font-size: 28rpx;
    color: #FF4444;
    font-weight: 500;
}

.delete-btn:disabled {
    color: #CCCCCC;
}

/* 消息选择框样式 */
.message-checkbox {
    margin-right: 12rpx;
    display: flex;
    align-items: flex-start;
    padding-top: 8rpx;
}

.checkbox {
    width: 40rpx;
    height: 40rpx;
    border: 2rpx solid #CCCCCC;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.checkbox.checked {
    background-color: #256BFA;
    border-color: #256BFA;
}

/* 调整消息项布局，为选择框留出空间 */
.chat-item {
    position: relative;
}

.chat-item .message {
    flex: 1;
}
</style>
