<template>
  <div
    class="container"
    :style="{ height: `calc(100% - ${currentBottomHeight}px)` }"
  >
    <div class="chat-bg"></div>
    <!-- 顶部导航 -->
    <div class="header-chat">
      <svg-icon class="page-icon" name="lf-arrow" @click="goBack" />
      <div class="header-title" v-if="wsStore.toUserInfo.type == 'group'"><span class="m-ellipsis">{{ wsStore.toUserInfo.sessionName || '群聊' }}</span>({{ groupMembersArr.length }})</div>
      <div v-else class="header-title">{{ wsStore.toUserInfo.nickname }}</div>
      <svg-icon class="page-icon" name="more" @click="goDetail" />
    </div>

    <!-- 群公告 -->
    <div class="groupNotice" v-if="!noticeRead && wsStore.toUserInfo.type == 'group' && wsStore.toUserInfo.notice" @click="showNotice = true">
      <div class="m-ellipsis">群公告：{{ wsStore.toUserInfo.notice }}</div>
      <svg-icon class="item-icon" name="right1" />
    </div>

    <!-- 聊天消息区域 -->
    <div class="chat-list" ref="chatListRef">
      <van-loading class="load-box" size="24px" v-if="wsStore.loading">加载中...</van-loading>
      <template v-else>
      <div v-for="(item, index) in imMessages" :key="index">
        <div class="chat-time">
          {{ item.createDate || formatTime(Date.now()) }}
        </div>
        <div class="box" v-if="item.contentType !== MsgType.MSG_TYPE.NOTICE">
          <div
            class="list-item"
            :class="isSender(item) ? '' : 'flex-reverse'"
          >
            <!-- 头像 -->
            <van-image
              class="list-img"
              :class="isSender(item) ? 'mr12' : 'ml12'"
              round
              :src="formatAvatarUrl(item)"
              @click="goToPage(item)"
            />
            <!-- 内容 -->
            <div class="list-cont">
              <div>{{ item.sender?item.sender.nickname: (item.nickname || item.fromUsername || "匿名用户") }}</div>

              <div v-if="!item.isTemp || item.from == walletStore.account" style="position: relative;"> 
                <!-- 文本消息 -->
                <div class="content" v-if="item.contentType === MsgType.MSG_TYPE.TEXT" @click="onLongPress(item)">
                  <span v-if="item.err" style="color: red;font-size: small;">{{item.messageType == MsgType.MESSAGE_TYPE_USER?'对方已不是您的好友':'您已不在群里'}}</span>
                  {{ item.content }}
                </div>

                <!-- 图片消息 -->
                <div
                  class="img-message"
                  v-else-if="item.contentType === MsgType.MSG_TYPE.IMAGE"
                >
                  <van-image
                    :src="item?.localUrl || IM_PATH + item.url"
                    style="max-width: 120px; border-radius: 8px"
                    @click="previewImage(item)"
                  />
                </div>

                <!-- 名片消息 -->
                <div
                  class="content card-message"
                  v-else-if="item.contentType === 3"
                >
                  <div class="card-title">名片</div>
                  <div class="card-name">{{ item.content }}</div>
                </div>

                <!-- 录音消息 -->
                <div
                  class="audio-message"
                  v-else-if="item.contentType === MsgType.MSG_TYPE.AUDIO"
                >
                  <messageAudio
                    :src="item?.localUrl || IM_PATH + item.url"
                    :isSender="isSender(item)"
                  />
                </div>
                <!-- 拍摄 -->
                <video class="video-message" :isSender="isSender(item)" controls v-else-if="item.contentType === MsgType.MSG_TYPE.VIDEO" :src="item?.localUrl || IM_PATH + item.url"></video>

                <!-- 语音消息 -->
                <div class="content" v-if="item.contentType === Constant.REJECT_AUDIO_ONLINE || item.contentType === Constant.REJECT_VIDEO_ONLINE">[对方拒绝]</div>
                <div class="content" v-if="item.contentType === Constant.CANCELL_AUDIO_ONLINE || item.contentType === Constant.CANCELL_VIDEO_ONLINE">[通话结束]</div>
                
                <div v-if="item.quote > 0" class="quotation">{{ item.quoteMsg?.content }}</div>
              </div>
              <!-- 阅后即焚消息 -->
              <div
                v-else
                class="burn-message"
                @click="viewBurnMessage(item)"
              >
                <!-- 未查看 -->
                <div v-if="!item.view && item.content" class="burn-mask">
                  阅后即焚，点击查看
                </div>

                <!-- 已查看且正在倒计时 -->
                <template v-else-if="item.view && item.countdown > 0 && item.content">
                  <!-- 文本类型 -->
                  <div v-if="item.contentType === MsgType.MSG_TYPE.TEXT" class="burn-content">
                    {{ item.content }}
                    <span class="burn-countdown">{{ item.countdown }}s</span>
                  </div>

                  <!-- 录音类型 -->
                  <div v-else-if="item.contentType === MsgType.MSG_TYPE.AUDIO" class="burn-audio">
                    <messageAudio
                      :src="item?.localUrl || IM_PATH + item.url"
                      :isSender="isSender(item)"
                    />
                    <span class="burn-countdown">{{ item.countdown }}s</span>
                  </div>
                </template>

                <!-- 倒计时结束 -->
                <div v-else class="burn-destroyed">
                  该消息已焚毁
                </div>
              </div>
            </div>
          </div>
        </div>
        <div class="chat-time" v-if="item.contentType === MsgType.MSG_TYPE.NOTICE">
          {{ item.content }}
        </div>
      </div>
      </template>
    </div>
    <!-- 群公告组件 -->
    <GroupNotice
      v-model:show="showNotice"
      :notice="wsStore.toUserInfo.notice"
      @close="handleNoticeClose"
    />
    <!-- @页面 -->
    <AtUserList ref="atList" @select="onSelectUser" />
    <!-- 撤回弹窗 -->
    <van-action-sheet
      v-model:show="showActionSheet"
      :actions="actions"
      cancel-text="取消"
      @select="onActionSelect"
    />
    <!-- @样式 -->
    <div class="assign" v-if="wsStore.toUserInfo.type == 'group' && wsStore.isassign" @click="changAssign">
      <div class="assign-text">有人@我</div>
    </div>
    <!-- 引用消息展示 -->
    <div v-if="quoteMsg" class="quote-box">
      <div class="quote-content">{{ quoteMsg.fromUsername}}：{{ renderQuoteContent(quoteMsg) }}</div>
      <span class="quote-close" @click="cancelQuote">✕</span>
    </div>
    <!-- 输入框 -->
    <div class="page-foot">
      <div class="flex-box">
        <!-- 录音/文字切换按钮 -->
        <svg-icon
          type="button"
          class="page-icon"
          :name="voiceMode ? 'keyboard' : 'voice'"
          @click="toggleVoiceMode"
        />

        <!-- 文字输入框 或 按住说话按钮 -->
        <div class="box-input">
          <template v-if="!voiceMode">
            <van-field
              rows="1"
              type="textarea"
              :border="false"
              autosize
              class="input"
              v-model="text"
              @focus="onFocus"
              placeholder="输入文本"
            />
            <!-- :disabled="deletefriend.includes(wsStore.toUserInfo.uuid)" -->
          </template>

          <template v-else>
            <div
              class="hold-talk-btn"
              @touchstart.prevent.stop="handleTouchStart"
              @touchmove.prevent.stop="handleTouchMove"
              @touchend.prevent.stop="handleTouchEnd"
            >
            按住说话
            </div>
          </template>
        </div>
        <van-button class="sendText"
          v-if="text.trim()"
          type="primary"
          size="small"
          round
          @click="sendMessageText"
        >
          发送
        </van-button>
        <template v-else>
          <svg-icon
            class="page-icon mr12 emoji-toggle"
            name="emoji"
            @click="toggleAppBox(1)"
          />
          <svg-icon v-if="showBurn" @click="closeMessaageBurning"
            class="page-icon-qx"
            name="qx"
          />
          <svg-icon v-else
            class="page-icon tools-toggle"
            name="add2"
            @click="toggleAppBox(2)"
          />
        </template>
      </div>
      <!-- 录音状态浮层 -->
      <div v-if="recording" class="recording-toast">
        <div class="mic-icon"></div>
        <div v-if="cancelRecording" class="cancel-msg">松开手指，取消发送</div>
        <div v-else class="send-msg">手指上滑，取消发送</div>
      </div>
      <!-- 表情面板 -->
      <div
        class="app-box"
        v-show="showEmoji"
        :style="{ height: `${appBoxHeight}px` }"
        ref="emojiRef"
      >
        <div>
          <span
            v-for="(emoji, index) in emojis"
            :key="index"
            class="emoji-item"
            @click="insertEmoji(emoji)"
          >
            {{ emoji }}
          </span>
        </div>
      </div>

      <!-- 工具栏面板 -->
      <div
        class="app-box"
        v-show="showTools"
        :style="{ height: `${appBoxHeight}px` }"
        ref="toolsRef"
      >
        <div class="tool-btn">
          <van-uploader :after-read="afterRead" :before-read="beforeRead">
            <svg-icon class="tool-icon" name="tp" />
          </van-uploader>
          <div>图片</div>
        </div>
        <div class="tool-btn" @click="chatVideo = true">
          <svg-icon class="tool-icon" name="ps" />
          <div>拍摄</div>
        </div>
        <div class="tool-btn" v-if="wsStore.toUserInfo.type == 'user'">
          <svg-icon
            class="tool-icon"
            name="yyth"
            @click="startAudioOnline(Constant.DIAL_AUDIO_ONLINE, 'audio')"
          />
          <div>语音通话</div>
        </div>
        <div class="tool-btn" v-if="wsStore.toUserInfo.type == 'user'">
          <svg-icon
            class="tool-icon"
            name="spth"
            @click="startAudioOnline(Constant.DIAL_VIDEO_ONLINE, 'video')"
          />
          <div>视频通话</div>
        </div>
        <!-- <div class="tool-btn">
          <svg-icon class="tool-icon" name="mp" />
          <div>名片</div>
        </div> -->
        <div class="tool-btn" @click="openMessageBurning">
          <svg-icon class="tool-icon" name="mp" />
          <div>阅后即焚</div>
        </div>
      </div>
    </div>
    <VideoRecorder
      :show="chatVideo"
      @closeVideo="chatVideo = false"
      @sendVideo="handleSendVideo"
    />
  </div>
</template>

<script setup> 
import { useRouter, useRoute } from "vue-router";
import { useWebSocketStore } from "@/stores/modules/webSocketStore.js";
import { useWalletStore } from "@/stores/modules/walletStore.js";
import { Keyboard } from "@capacitor/keyboard";
import { Capacitor } from "@capacitor/core";
import * as MsgType from "@/common/constant/msgType";
import messageAudio from "@/views/im/components/messageAudio/index.vue";
import { showToast, showImagePreview } from "vant";
import { useWebRTCStore } from "@/stores/modules/webrtcStore";
import * as Constant from "@/common/constant/Constant";
import { soundVoice } from "@/utils/notifications.js";
import AtUserList from "./components/AtUserList/index.vue";
import GroupNotice from "./components/GroupNotice/index.vue";
import VideoRecorder from "./components/VideoRecorder/index.vue";
import { messageRevoke } from '@/api/path/im.api';

const IM_PATH = import.meta.env.VITE_IM_PATH_FIlE;
// 路由 & store
const router = useRouter();
const route = useRoute();
const wsStore = useWebSocketStore();
const walletStore = useWalletStore();
const rtcStore = useWebRTCStore();

// 输入框文本
const text = ref("");

// 状态管理
const keyboardHeight = ref(0);
const showEmoji = ref(false);
const showTools = ref(false);
const appBoxHeight = ref(210);
const chatListRef = ref(null);
const emojiRef = ref(null);
const toolsRef = ref(null);
// 听筒模式
const earMode = ref(false);
// @成员
const ccMsg = ref([]);
// 消息置顶
const stickTop = ref(0);
// 引用消息
const quoteMsg = ref(null);
// 表情数组
const emojis = [
  "😀", "😃", "😄", "😁", "😆", "😅", "😂", "🤣",
  "😊", "😇", "🙂", "🙃", "😉", "😌", "😍","😜","🤪","🫣","🤔","🤤","🥲","😋",
  "😀", "😃", "😄", "😁", "😆", "😅", "😂", "🤣",
];
const atList = ref();
const showBurn = ref(false)  // 阅后即焚是否开启
const showNotice = ref(false);
const noticeRead = ref(false);

const currentMsg = ref('');
const showActionSheet = ref(false)
const actions = ref([])
const chatVideo = ref(false);

const formatAvatarUrl = (item) => {
  const url = item?.sender?.avatar || item?.fromAvatar || ''
  if (/^https?:\/\//.test(url)) {
    return url
  }
  return IM_PATH + url
}

const isSender = (item) => {
  if(item.align == 'left'){
    return true
  }else{
    return false
  }
};

const imMessages = computed(() =>{
  wsStore.funUpdateUnread(wsStore.toUserInfo.uuid);
  return wsStore.messages.map(item=>{
    item.quoteMsg = null;
    if (item.quote>0){
      item.quoteMsg = wsStore.messages.find(val => val.id == item.quote)
    }
    return item;
  });
})
const changAssign = () => {
  wsStore.isassign = '';
}


// 滚动到底部
const scrollToBottom = () => {
  nextTick(() => {
    if (chatListRef.value) {
      const el = chatListRef.value;
      // el.scrollTop = el.scrollHeight;
      setTimeout(() => {
        el.scrollTo({
          left: 0, top: el.scrollHeight + 100,behavior: 'smooth'
        });
      }, 200);
    }
  });
};
watch(
  () => wsStore.indexs,
  (newVal,oldVal) => {
    if (newVal !== oldVal) {
      scrollToBottom();
    }
  }
);

watch(
  () => rtcStore.isEarpieceMode,
  (newVal) => {
    earMode.value = newVal;
  }
);

// 平台判断
const isMobile = Capacitor.getPlatform() !== "web";

// 计算当前底部总高度
const currentBottomHeight = computed(() => {
  if (keyboardHeight.value > 0) return keyboardHeight.value;
  if (showEmoji.value || showTools.value) return appBoxHeight.value;
  return 0;
});

// 切换表情/工具面板
const toggleAppBox = async (type) => {
  if(!wsStore.verifyChatAuth(wsStore.toUserInfo.uuid)){
    showToast(`${wsStore.toUserInfo.type == 'user' ? '对方已删除' : '您已不在群聊里面'}`);
    return;
  }
  voiceMode.value = false;
  if (isMobile) await Keyboard.hide();
  keyboardHeight.value = 0;
  if (type === 1) {
    showEmoji.value = !showEmoji.value;
    showTools.value = false;
  } else {
    showTools.value = !showTools.value;
    showEmoji.value = false;
  }
  scrollToBottom();
};

// 插入表情
const insertEmoji = (emoji) => {
  text.value += emoji;
};

// 预览图片
const previewImage = (item) => {
  const imageList = wsStore.messages
    .filter((m) => m.contentType === MsgType.MSG_TYPE.IMAGE)
    .map((m) => m.localUrl || IM_PATH + m.url);

  const index = imageList.findIndex(
    (url) => url === (item.localUrl || IM_PATH + item.url)
  );

  showImagePreview({
    images: imageList,
    startPosition: index,
  });
};

const onFocus = () => {
  // 隐藏所有面板
  showEmoji.value = false;
  showTools.value = false;
  if (isMobile) setupKeyboardListeners();
  scrollToBottom();
};

// 键盘监听
const setupKeyboardListeners = async () => {
  Keyboard.addListener("keyboardWillShow", (info) => {
    keyboardHeight.value = info.keyboardHeight;
  });

  Keyboard.addListener("keyboardWillHide", () => {
    keyboardHeight.value = 0;
  });
};

// 设置消息引用
const handleQuote = (item) => { 
  quoteMsg.value = item //imMessages.find(m => m.id == item.id)
};
// 取消消息引用
const cancelQuote = () => { 
  quoteMsg.value = null; // 发送即删除
};
// 切换输出模式 true 听筒，false 扬声器
const changeAudioOutputMode = async (flag) => { 
  await rtcStore.setAudioOutputToEarpiece(flag);
};
// 群消息置顶操作
const groupMessageStickTop = (message)=>{
  if(wsStore.toUserInfo.type == 'user'){
    return;
  }
  wsStore.sendMessage({
    content: JSON.stringify({ 
      content: message.content,
      id: message.id, // 消息id
      sticks: message.id, // 置顶
    }), 
    contentType: message.contentType,
    messageType: MsgType.MESSAGE_STICKY_GROUP,
  });
  scrollToBottom();
}
// 开启消息阅后即焚
const openMessageBurning = ()=>{
  showBurn.value = true
  showTools.value = false
}
// 关闭消息阅后即焚
const closeMessaageBurning = ()=>{
  showBurn.value = false
}
// 撤回消息
const revokeMessage = async (message)=>{
  try {
    const res = await messageRevoke({
      messageId:message.id + '',
      uuid:message.fromUuid,
      toUuid:message.toUuid,
      messageType:message.messageType
    })
    if(res.code == 200){
      wsStore.sendMessage({
        content: JSON.stringify({ 
          // content: '',
          // msgId: message.id + '',
          id: message.id,
          fromUsername:message.fromUsername,
        }), 
        contentType: MsgType.MSG_TYPE.NOTICE, 
        messageType: wsStore.toUserInfo.type == 'user'?MsgType.MESSAGE_REVOKE:MsgType.MESSAGE_REVOKE_GROUP,
      });
    }else{
      showToast('撤回失败')
    }
  } catch (error) {
    showToast('撤回失败')
  }
  
}
// 点击查看阅后即焚消息
const viewBurnMessage = (message) => {
  // console.log("查看阅后即焚消息:", message);
  if (!message.view) {
    message.view = true;
    message.countdown = 15; // 倒计时

    // 如果是录音，可以自动播放
    if (message.contentType === MsgType.MSG_TYPE.AUDIO) {
      const audio = new Audio(message?.localUrl || IM_PATH + message.url);
      audio.play();
    }

    const timer = setInterval(() => {
      if (message.countdown > 1) {
        message.countdown--;
      } else {
        clearInterval(timer);
        destroyMessage(message); // 发撤回通知
        message.content = '';
        message.countdown = 0; // 标记焚毁
      }
    }, 1000);
  }
};

// 真正销毁
const destroyMessage = (message) => {
  message.content = ''; // 先清空本地显示
  // 如果是群消息, 本地更新消息销毁
  if (message.messageType ==  MsgType.MESSAGE_TYPE_GROUP) {
    const msg = {isTemp: true, content: '', contentType: message.contentType, messageType: message.messageType};
    // 更新消息
    wsStore.modifyMessage(msg, message.id, wsStore.toUserInfo.uuid);
    // 更新会话列表
    wsStore.updateSessionNewMessage(msg, wsStore.toUserInfo.uuid);
    return;
  }
  wsStore.sendMessage({
    content: JSON.stringify({ 
      // content: '',
      // msgId: message.id + '',
      id: message.id,
      isTemp: true,
    }),
    contentType: MsgType.MSG_TYPE.NOTICE, 
    messageType: wsStore.toUserInfo.type == 'user'
      ? MsgType.MESSAGE_REVOKE
      : MsgType.MESSAGE_REVOKE_GROUP,
  });
};
// 当子组件关闭时触发---关闭群公告
const handleNoticeClose = () => {
  showNotice.value = false
  // noticeRead.value = true
}

// 录音相关状态
const voiceMode = ref(false); // false: 文字输入, true: 语音模式
const recording = ref(false);
const cancelRecording = ref(false);
const startY = ref(0);
let mediaRecorder = null;
let audioChunks = [];

// 切换文字/语音输入模式
const toggleVoiceMode = () => {
  if(!wsStore.verifyChatAuth(wsStore.toUserInfo.uuid)){
    showToast(`${wsStore.toUserInfo.type == 'user' ? '对方已删除' : '您已不在群聊里面'}`);
    return;
  }
  voiceMode.value = !voiceMode.value;
  // 切换时关闭表情和工具面板，隐藏键盘
  showEmoji.value = false;
  showTools.value = false;
  if (isMobile) Keyboard.hide();
  keyboardHeight.value = 0;
  scrollToBottom();
};

// 录音事件
const handleTouchStart = async (e) => {
  startY.value = e.touches[0].clientY;
  cancelRecording.value = false;
  recording.value = true;
  audioChunks = [];

  try {
    const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
    mediaRecorder = new MediaRecorder(stream, {
      mimeType: "audio/webm; codecs=opus",
    });
    mediaRecorder.ondataavailable = (ev) => {
      audioChunks.push(ev.data);
    };
    mediaRecorder.start(1000);
    console.log("开始录音");
  } catch (err) {
    console.error("麦克风权限获取失败", err);
    recording.value = false;
  }
};
// 录音
const handleTouchMove = (e) => {
  const currentY = e.touches[0].clientY;
  if (startY.value - currentY > 50) {
    cancelRecording.value = true;
  } else {
    cancelRecording.value = false;
  }
};

// 录音发送
const handleTouchEnd = () => {
  if (!mediaRecorder) return;
  mediaRecorder.stop();
  mediaRecorder.stream.getTracks().forEach((t) => t.stop());
  recording.value = false;

  mediaRecorder.onstop = async () => {
    if (cancelRecording.value) {
      console.log("录音取消");
      return;
    }
    if (audioChunks.length === 0) return;
    const audioBlob = new Blob(audioChunks, { type: "audio/webm" });
    const arrayBuffer = await audioBlob.arrayBuffer();
    const audioData = new Uint8Array(arrayBuffer);

    wsStore.sendMessage({
      // content: "",
      content: JSON.stringify({ 
        content: "",
        msgId: `ms${Date.now()}`, // 消息id
        quote: quoteMsg.value?.id, // 引用消息id
        cc: wsStore.toUserInfo.type == 'user'?"":ccMsg.value.join(","), // @成员
        isTemp: showBurn.value === true, // 消息阅后即焚
      }), 
      contentType: MsgType.MSG_TYPE.AUDIO,
      messageType: wsStore.toUserInfo.type == 'user'?MsgType.MESSAGE_TYPE_USER:(ccMsg.value.length> 0?MsgType.MESSAGE_CC_GROUP:MsgType.MESSAGE_TYPE_GROUP),
      fileSuffix: "wav", // 使用webm后缀更准确
      file: audioData, // 将Uint8Array转为普通数组
    });
    cancelQuote(); // 取消引用
    ccMsg.value = []; // 清空 @成员
    scrollToBottom();
    console.log("语音已发送");
  };
};

// 监听输入 @
watch(
  () => text.value,
  (val) => {
    if (val.slice(-1) === '@' && wsStore.toUserInfo.type != 'user') {
      atList.value.open(); // 打开选人弹窗
    }
  }
);
// 选择用户回填输入框
const onSelectUser = (user) => {
  text.value += `${user.nickname} `;
  ccMsg.value.push(user)
};

const onLongPress = (msg) => {
  console.log(msg)
  if(msg.fromUuid != walletStore.account){
    actions.value = [
      { name: "复制", key: "copy" },
      { name: "引用", key: "quote" },
      // { name: "置顶", key: "stick" },
    ]
  }else{
    actions.value = [
      { name: "复制", key: "copy" },
      { name: "撤回", key: "revoke" },
      { name: "引用", key: "quote" },
      // { name: "置顶", key: "stick" },
    ]
  }
  currentMsg.value = msg;
  showActionSheet.value = true;
};
const onActionSelect = (action) => {
  if (!currentMsg.value) return;

  if (action.key === "copy") {
    navigator.clipboard.writeText(currentMsg.value.content);
    showToast("已复制");
  } else if (action.key === "revoke") {
    revokeMessage(currentMsg.value);
    currentMsg.value.revoked = true;
  } else if(action.key === "quote") {
    // 引用
    handleQuote(currentMsg.value)
  }
  showActionSheet.value = false;
};
// 渲染引用的内容（文字/图片等）
const renderQuoteContent = (msg) => {
  if (msg.contentType === MsgType.MSG_TYPE.TEXT) {
    return msg.content;
  } else if (msg.contentType === MsgType.MSG_TYPE.IMAGE) {
    return "[图片]";
  } else if (msg.contentType === MsgType.MSG_TYPE.AUDIO) {
    return "[语音]";
  } else {
    return "[消息]";
  }
};

// 发送消息
const sendMessageText = () => {
  if(!wsStore.verifyChatAuth(wsStore.toUserInfo.uuid)){
    showToast(`${wsStore.toUserInfo.type == 'user' ? '对方已删除' : '您已不在群聊里面'}`);
    return;
  }
  if (!text.value.trim()) return;
  
  // 检测消息@成员
  let cc = [];
  if(ccMsg.value.length>0 && wsStore.toUserInfo.type != 'user'){
    const matchs = text.value.match(/(@([^ ]+) )/ig) || [];
    cc = ccMsg.value.filter(val=> matchs.includes(`@${val.nickname} `)).map(val=>val.userId);
    // 检测@所有人
    if(matchs.includes(`@所有人 `)){
      cc = [0]
    }
  }
// console.log(wsStore.toUserInfo);
  const message = {
    content: JSON.stringify({ 
      content: text.value,
      msgId: `ms${Date.now()}`, // 消息id
      quote: quoteMsg.value?.id, // 引用消息id
      cc: wsStore.toUserInfo.type == 'user'?"":cc.join(","), // @成员
      isTemp: showBurn.value === true, // 消息阅后即焚
    }), 
    contentType: MsgType.MSG_TYPE.TEXT, // 1: 文本消息
    messageType: wsStore.toUserInfo.type == 'user'?MsgType.MESSAGE_TYPE_USER:(cc.length> 0?MsgType.MESSAGE_CC_GROUP:MsgType.MESSAGE_TYPE_GROUP),
  };
  wsStore.sendMessage(message);
  text.value = "";
  cancelQuote(); // 取消引用
  ccMsg.value = []; // 清空 @成员
  scrollToBottom();
};
// 发送图片消息
const afterRead = async (file) => { 
  if(!wsStore.verifyChatAuth(wsStore.toUserInfo.uuid)){
    showToast(`${wsStore.toUserInfo.type == 'user' ? '对方已删除' : '您已不在群聊里面'}`);
    return;
  }
  const arrayBuffer = await file.file.arrayBuffer();
  const message = {
    // content: text.value, // 如果有文本内容
    content: JSON.stringify({ 
      content: text.value,
      msgId: `ms${Date.now()}`, // 消息id
      quote: quoteMsg.value?.id, // 引用消息id
      cc: wsStore.toUserInfo.type == 'user'?"":ccMsg.value.join(","), // @成员
      isTemp: showBurn.value === true, // 消息阅后即焚
    }), 
    contentType: MsgType.MSG_TYPE.IMAGE, // 音频消息类型
    messageType: wsStore.toUserInfo.type == 'user'?MsgType.MESSAGE_TYPE_USER:(ccMsg.value.length> 0?MsgType.MESSAGE_CC_GROUP:MsgType.MESSAGE_TYPE_GROUP),
    fileSuffix: file.file.type, // 使用webm后缀更准确
    file: new Uint8Array(arrayBuffer), // 将Uint8Array转为普通数组
  };
  cancelQuote(); // 取消引用
  ccMsg.value = []; // 清空 @成员
  wsStore.sendMessage(message);
  scrollToBottom();
};
// 图片类型
const beforeRead = (file) => {
  const realFile = file.file || file;
  const type = realFile.type;
  const name = realFile.name || "";

  if (type === "image/svg+xml" || name.endsWith(".svg")) {
    showToast("不支持上传 SVG 格式的图片");
    return false;
  }
  return true;
};
// 发送视频
const handleSendVideo = async (blob) =>{
  chatVideo.value = false;
  const arrayBuffer = await blob.arrayBuffer();
  const audioData = new Uint8Array(arrayBuffer);

  wsStore.sendMessage({
    // content: "",
    content: JSON.stringify({ 
      content: "",
      msgId: `ms${Date.now()}`, // 消息id
      quote: quoteMsg.value?.id, // 引用消息id
      cc: wsStore.toUserInfo.type == 'user'?"":ccMsg.value.join(","), // @成员
      isTemp: showBurn.value === true, // 消息阅后即焚
    }), 
    contentType: MsgType.MSG_TYPE.VIDEO,
    messageType: wsStore.toUserInfo.type == 'user'?MsgType.MESSAGE_TYPE_USER:(ccMsg.value.length> 0?MsgType.MESSAGE_CC_GROUP:MsgType.MESSAGE_TYPE_GROUP),
    fileSuffix: "mp4", // 使用webm后缀更准确
    file: audioData, // 将Uint8Array转为普通数组
  });
  cancelQuote(); // 取消引用
  ccMsg.value = []; // 清空 @成员
  scrollToBottom();
  console.log("视频已发送");
}

//  创建呼叫:开启语音电话: 调试用，正式逻辑读src/views/im/hook/messagesHook.js
// ==== 1. 发起语音通话 ====
const startAudioOnline = async (contentType, streamType) => {
  // 清理被呼叫者信息
  wsStore.toUserInfo.sender = null;
  // 调起通话界面
  rtcStore.streamType = streamType
  rtcStore.imSate.videoCallModal = true;
  // 设置被呼叫对象
  rtcStore.imSate.callAvatar = wsStore.toUserInfo.avatar;
  rtcStore.imSate.callName = wsStore.toUserInfo.nickname;
  // 设置呼叫者/被呼叫者
  rtcStore.isCaller = true;
  // 通知被呼叫者
  wsStore.sendMessage({
    messageType: wsStore.toUserInfo.type == 'user'?MsgType.MESSAGE_TYPE_USER:MsgType.MESSAGE_TYPE_GROUP,
    contentType,
    type: Constant.MESSAGE_TRANS_TYPE,
    avatar: walletStore.avatar,
    content: JSON.stringify({
      content: walletStore.username,
      sender: walletStore.account,
    })
  });
  // 播放铃声
  soundVoice.play() 
  // 开启本地视频
  if (streamType === 'video') {
    rtcStore.getUserMedia({ audio: true, video: true })
  }
};

// 时间格式化
const formatTime = (timestamp) => {
  const date = new Date(timestamp);
  const h = date.getHours().toString().padStart(2, "0");
  const m = date.getMinutes().toString().padStart(2, "0");
  return `${h}:${m}`;
};
const groupMembersArr = computed(() => wsStore.groupMembersList[wsStore.toUserInfo.uuid] || []);

// 页面生命周期
onMounted(async () => {
  wsStore.toUserInfo.uuid = route.query.uuid;
  if (wsStore.toUserInfo.type == 'group') {
    await wsStore.fetchGroupMembers(route.query.uuid);
  }
  await wsStore.getMessages({
    uuid: route.query.uuid,
    messageType: wsStore.toUserInfo.type == 'user'?1:2, //1:个人  2:群组
    friendUsername: walletStore.account
  });
  scrollToBottom();
  document.addEventListener("click", handleClickOutside);
});

onUnmounted(() => {
  if (isMobile) Keyboard.removeAllListeners();
});
onBeforeUnmount(() => {
  document.removeEventListener("click", handleClickOutside);
});

// 判断是否点击在元素外
const handleClickOutside = (event) => {
  const emojiEl = emojiRef.value;
  const toolsEl = toolsRef.value;
  const target = event.target;

  if (
    showEmoji.value &&
    emojiEl &&
    !emojiEl.contains(target) &&
    !target.closest(".emoji-toggle")
  ) {
    showEmoji.value = false;
  }

  if (
    showTools.value &&
    toolsEl &&
    !toolsEl.contains(target) &&
    !target.closest(".tools-toggle")
  ) {
    showTools.value = false;
  }
};

// 页面跳转
const goToPage = (item) => {
  if(!(isSender(item))) return;
  router.push({
    path: 'personal',
    query:{
      uuid:wsStore.toUserInfo.type == 'user'?wsStore.toUserInfo.uuid:item.fromUuid,
      type:2
    }
  })
}
const goBack = () => router.push("im");
const goDetail = () =>{
  if(!wsStore.verifyChatAuth(wsStore.toUserInfo.uuid)){
    showToast(`${wsStore.toUserInfo.type == 'user' ? '对方已删除' : '您已不在群聊里面'}`);
    return;
  }
  router.push({
    path: 'detail',
    query:{ status:wsStore.toUserInfo.type == 'user'?1:2 }
  }) // 1:单聊  2：群聊
}
</script>

<style lang="less" scoped>
.load-box{
  text-align: center !important;
  margin-top: 50px !important;
}
.mr12 {
  margin-right: 12px;
}
.ml12 {
  margin-left: 12px;
}
.text-right {
  text-align: right;
}
.page-icon {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
}
.page-icon-qx{
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}
.container {
  display: flex;
  flex-direction: column;
  .chat-bg {
    height: 126px;
    background: linear-gradient(90deg, @theme-color1 0%, #40a4fb 100%);
    position: absolute;
    left: 0;
    right: 0;
    z-index: -1;
  }
  .header-chat {
    padding-top: 56px;
    margin: 0 16px;
    display: flex;
    align-items: center;
    color: @theme-color1;
    .header-title {
      flex: 1;
      font-family:
        PingFang SC,
        PingFang SC;
      font-weight: 500;
      font-size: 19px;
      color: #ffffff;
      text-align: center;
      margin: 0 16px;
      display: flex;
      overflow: hidden;
      justify-content: center;
      align-items: center;
    }
  }
  .chat-list {
    background: #f7f8fa;
    border-radius: 30px 30px 0 0;
    flex: 1;
    overflow: auto;
    margin-top: 20px;
    padding: 0 16px 24px;
    .chat-time {
      font-family:
        PingFang SC,
        PingFang SC;
      font-weight: 400;
      font-size: 12px;
      color: #8d8d8d;
      text-align: center;
      margin: 20px 0;
    }
    .box {
      .list-item {
        display: flex;
        margin-bottom: 24px;
        .list-img {
          width: 44px;
          height: 44px;
          flex-shrink: 0;
        }
        .list-cont {
          font-family:
            PingFang SC,
            PingFang SC;
          font-weight: 400;
          font-size: 12px;
          color: #8d8d8d;
          max-width: 70%;
          display: flex;
          flex-direction: column;
          align-items: flex-start;
          .business-card {
            width: 199px;
            height: 93px;
            background: #ffffff;
            border-radius: 10px;
            margin-top: 8px;
            padding: 10px;
            box-sizing: border-box;
            .business-card-cont {
              display: flex;
              align-items: center;
              font-family:
                PingFang SC,
                PingFang SC;
              font-weight: 400;
              font-size: 15px;
              color: #000000;
            }
            .line {
              height: 1px;
              background: #f2f2f2;
              margin: 10px 0 6px;
            }
            .business-card-text {
              font-family:
                PingFang SC,
                PingFang SC;
              font-weight: 400;
              font-size: 10px;
              color: #8d8d8d;
            }
          }
          .content {
            background: #ffffff; // 对方消息背景白色
            color: #000;
            border-radius: 10px;
            margin-top: 8px;
            padding: 8px 17px;
            word-break: break-word;
            white-space: pre-wrap;
            max-width: 100%;
            font-family:
              PingFang SC,
              PingFang SC;
            font-weight: 400;
            font-size: 15px;
          }
          .img-message {
            margin-top: 8px;
          }
          .video-message{
            margin-top: 8px;
            width: 200px;
            height: 200px;
            // transform: scaleX(-1);
          }
        }
      }
      .withdrawal {
        display: flex;
        justify-content: center;
        margin-bottom: 24px;
        .withdrawal-text {
          width: 142px;
          height: 29px;
          line-height: 29px;
          box-sizing: border-box;
          background: #f2f2f2;
          border-radius: 4px;
          font-family:
            PingFang SC,
            PingFang SC;
          font-weight: 400;
          font-size: 12px;
          color: #8d8d8d;
          text-align: center;
        }
      }
      .flex-reverse {
        flex-direction: row-reverse;
      }
      .flex-reverse .list-cont {
        align-items: flex-end;
        .content {
          background: #4d71ff; // 自己的消息是蓝色
          color: #ffffff; // 白字
        }
      }
    }
  }
  .chat-list::-webkit-scrollbar {
    width: 0;
  }
  .page-foot {
    position: relative;
    background-color: #fff;
    .flex-box {
      padding: 8px 16px 16px;
      display: flex;
      align-items: center;
      box-sizing: border-box;
      .box-input{
        flex: 1;
        margin: 0 12px;
      }
      .input {
        flex: 1;
        background: #f2f2f2;
        border-radius: 17px;
        border: 1px solid #d8d8d8;
        padding: 6px 16px;
        font-weight: 500;
        font-size: 15px;
        overflow-y: auto;
      }
    }
  }
}
.app-box {
  position: fixed;
  bottom: 210px;
  left: 0;
  right: 0;
  background: white;
  transition: transform 0.3s ease;
  transform: translateY(100%);
  display: flex;
  flex-wrap: wrap;
  padding: 10px 16px;
  overflow-y: auto;
  box-sizing: border-box;
  &.visible {
    transform: translateY(0);
  }
  .tool-btn {
    width: calc(100% / 4);
    display: flex;
    flex-direction: column;
    align-items: center;
    font-family:
      PingFang SC,
      PingFang SC;
    font-weight: 400;
    font-size: 12px;
    color: #000000;
    .tool-icon {
      width: 56px;
      height: 56px;
      margin-bottom: 4px;
    }
  }
  .emoji-item{
    font-size: 20px;
    margin: 0 4px;
  }
}
.app-box::-webkit-scrollbar {
    width: 0;
  }

.page-foot {
  position: relative;
  z-index: 10; /* 确保输入框在上层 */
}


.local-video {
  position: absolute;
  bottom: 20px;
  right: 20px;
  width: 200px;
  height: auto;
  border: 2px solid white;
  border-radius: 8px;
}
/* 按住说话按钮 */
.hold-talk-btn {
  flex: 1;
  text-align: center;
  background: #f5f5f5;
  padding: 6px 16px;
  border-radius: 17px;
  color: #666;
  font-weight: 500;
  font-size: 15px;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  line-height: 24px;
  border: 1px solid #f5f5f5;
}

/* 录音中的浮层提示 */
.recording-toast {
  position: fixed;
  bottom: 80px;
  left: 50%;
  transform: translateX(-50%);
  width: 160px;
  min-height: 160px;
  background: rgba(0, 0, 0, 0.85);
  border-radius: 12px;
  padding: 16px;
  box-sizing: border-box;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;

  .mic-icon {
    width: 60px;
    height: 60px;
    background: url("https://img.icons8.com/ios-filled/100/ffffff/microphone.png") no-repeat center center;
    background-size: contain;
    margin-bottom: 16px;
  }

  .send-msg {
    color: #fff;
    font-size: 14px;
  }

  .cancel-msg {
    color: #ff4d4f;
    font-size: 14px;
  }
}
.m-ellipsis{
    white-space: nowrap;   /* 不换行 */
    overflow: hidden;      /* 超出隐藏 */
    text-overflow: ellipsis; /* 超出显示省略号 */
  }
.groupNotice{
  margin-top: 15px;
  background-color: #fff;
  height: 40px;
  line-height: 40px;
  font-family: PingFang SC, PingFang SC;
  font-weight: 400;
  font-size: 12px;
  color: #000000;
  padding: 0 16px;
  box-sizing: border-box;
  display: flex;
  justify-content: space-between;
  align-items: center;
  text-align: center;
  .item-icon{
    width: 20px;
    height: 20px;
    color: #969799;
  }
}
.revoked-msg {
  color: #999;
  font-size: 12px;
  font-style: italic;
  text-align: center;
  margin: 5px 0;
}
.burn-tag {
  font-size: 10px;
  color: red;
  margin-left: 6px;
}
.assign{
  margin-bottom: 20px;
  display: flex;
  justify-content: flex-end;
  .assign-text{
    color: #fff;
    background: #4765dd;
    border-radius: 30px 0 0 30px;
    padding: 3px 10px;
  }
}
// 引用样式
.quote-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: #f2f2f2;
  border-radius: 6px;
  padding: 4px 16px;
  font-size: 14px;
  color: #969696;
  font-size: 12px;
}
.quote-content {
  margin-bottom: 2px;
}
.quotation{
  background: #f2f2f2;
  border-radius: 5px;
  padding: 5px 10px;
  margin-top: 5px;
}
// 阅后即焚样式
.burn-message {
  background: #fff;
  color: #000;
  border-radius: 10px;
  margin-top: 8px;
  padding: 8px 14px;
  max-width: 100%;
  font-size: 15px;
  position: relative;
  cursor: pointer;
  word-break: break-word;
  transition: all 0.3s ease;

  &.self {
    background: #4d71ff;
    color: #fff;
  }

  .burn-mask {
    text-align: center;
    color: #999;
    font-size: 14px;
    filter: blur(0px);
  }

  .burn-content,.burn-audio {
    position: relative;
  }
  .burn-countdown {
    position: absolute;
    font-size: 12px;
    color: #ff5b5b;
    margin-left: 6px;
    top: -15px;
    right: -20px;
  }
  .burn-destroyed {
    color: #999;
    font-size: 13px;
    text-align: center;
  }
}
.sendText{
  border-radius: 5px;
  background-color: #4765dd;
  padding: 0 16px;
  height: 30px;
  line-height: 30px;
}
:deep(.van-button:before){
  border: none;
}
</style>