<template>
  <div class="flex h-dvh flex-col relative overflow-hidden">
    <!-- 顶部自定义导航栏 -->
    <div class="absolute top-0 left-0 w-full z-10">
      <ChatTopNavBar ref="topNavBarRef" :mainPageDataModel="mainPageDataModel" />
    </div>

    <div ref="mainScrollRef"
      class="min-h-0 flex-1 overflow-y-auto overscroll-contain scrollbar-none [-ms-overflow-style:none] [&::-webkit-scrollbar]:hidden"
      @scroll="handleScroll" @touchstart.capture="handleScrollAreaTouchStart" @touchstart="handleScrollAreaTouchStart"
      @touchmove="handleScrollAreaTouchMove">
      <div class="relative transition-all duration-300 ease-in-out bg-cover bg-center bg-no-repeat"
        :class="{ 'sticky top-0 z-100': isHeaderCollapsed }"
        :style="{ height: isHeaderCollapsed ? '50px' : '252px', backgroundImage: mainPageDataModel?.initPageImages?.backgroundImageUrl ? `url(${mainPageDataModel.initPageImages.backgroundImageUrl})` : 'none' }">
        <div class="absolute bottom-0 left-0 right-0 flex-1">
          <div class="px-[12px] pt-[12px] transition-all duration-300"
            :class="{ 'opacity-0 max-h-0 overflow-hidden pt-0': isHeaderCollapsed }">
            <Welcome :mainPageDataModel="mainPageDataModel" />
          </div>
          <div style="margin-bottom: -1px">
            <AiTabSwitch v-model="tabIndex" :list="tabList" @change="handleChange" />
          </div>
        </div>
      </div>

      <!-- 发现页 -->
      <div v-show="tabIndex === 0" class="min-h-0 flex-1 overflow-hidden"
        @touchstart.capture="handleScrollAreaTouchStart" @touchstart="handleScrollAreaTouchStart"
        @touchmove="handleScrollAreaTouchMove">
        <Discovery @scroll-touch-start="handleScrollAreaTouchStart" @scroll-touch="handleScrollAreaTouchMove" />
      </div>

      <!-- 消息列表（可滚动区域） -->
      <div v-show="tabIndex === 1" class="min-h-0 flex-1 overflow-hidden" :scroll-top="scrollTop" @scroll="handleScroll"
        @scrolltolower="handleScrollToLower" @touchstart.capture="handleScrollAreaTouchStart"
        @touchstart="handleScrollAreaTouchStart" @touchmove="handleScrollAreaTouchMove">
        <div class="area-msg-list-content" v-for="item in chatMsgList" :key="item.msgId" :id="item.msgId">
          <template v-if="item.msgType === MessageRole.AI">
            <ChatCardAI class="flex justify-start" :key="`ai-${item.msgId}-${item.msg ? item.msg.length : 0}`" :text="item.componentName && isLongTextCard(item.componentName)
              ? ''
              : item.msg || ''
              " :isLoading="item.isLoading">
              <template #content v-if="
                item.toolCall ||
                (item.componentName && isLongTextCard(item.componentName))
              ">
                <LongTextGuideCardPreview v-if="
                  item.componentName && isLongTextCard(item.componentName)
                " :componentName="item.componentName" />

                <QuickBookingComponent v-if="
                  item.toolCall &&
                  item.toolCall.componentName === CompName.quickBookingCard
                " />
                <DiscoveryCardComponent v-else-if="
                  item.toolCall &&
                  item.toolCall.componentName === CompName.discoveryCard
                " />
                <CreateServiceOrder v-else-if="
                  item.toolCall &&
                  item.toolCall.componentName === CompName.callServiceCard
                " :toolCall="item.toolCall" />
                <OpenMapComponent v-else-if="
                  item.toolCall &&
                  item.toolCall.componentName === CompName.mapCard
                " />
                <GeneratorPhotoComponent v-else-if="
                  item.toolCall &&
                  item.toolCall.componentName ===
                  CompName.aigcPhotoGeneratorCard
                " :toolCall="item.toolCall" />
                <AigcPhotoCard v-else-if="
                  item.toolCall &&
                  item.toolCall.componentName === CompName.videoCard
                " :toolCall="item.toolCall" />

                <Feedback v-else-if="
                  item.toolCall &&
                  item.toolCall.componentName === CompName.feedbackCard
                " :toolCall="item.toolCall" />
                <DetailCardComponent v-else-if="
                  item.toolCall &&
                  item.toolCall.componentName ===
                  CompName.pictureAndCommodityCard
                " :toolCall="item.toolCall" />
                <AddCarCard v-else-if="
                  item.toolCall &&
                  item.toolCall.componentName ===
                  CompName.enterLicensePlateCard
                " :toolCall="item.toolCall" />
                <SurveyQuestionnaire v-else-if="
                  item.toolCall &&
                  item.toolCall.componentName ===
                  CompName.callSurveyQuestionnaire
                " :toolCall="item.toolCall" />
              </template>

              <template #footer>
                <!-- 这个是底部 -->
                <AttachListComponent v-if="item.question" :question="item.question" />
              </template>
            </ChatCardAI>
          </template>

          <template v-else-if="item.msgType === MessageRole.ME">
            <ChatCardMine class="flex justify-end" :text="item.msg" />
          </template>

          <template v-else>
            <ChatCardOther class="flex justify-center" :text="item.msg">
              <ChatGuide v-if="chatMsgList.length < 2" />
              <ActivityListComponent v-if="
                mainPageDataModel.activityList &&
                mainPageDataModel.activityList.length
              " :activityList="mainPageDataModel.activityList" />

              <!-- 先不展示了，等后续有需求再加回来 false -->
              <RecommendPostsComponent v-if="
                false &&
                mainPageDataModel.recommendTheme &&
                mainPageDataModel.recommendTheme.length
              " :recommendThemeList="mainPageDataModel.recommendTheme" />
            </ChatCardOther>
          </template>
        </div>
      </div>
    </div>

    <!-- 输入框区域 -->
    <div class="mt-auto shrink-0">
      <ChatQuickAccess />
      <ChatInputArea ref="inputAreaRef" v-model="inputMessage" :holdKeyboard="holdKeyboard"
        :is-session-active="isSessionActive" :stop-request="stopRequest" @send="sendMessageAction"
        @noHideKeyboard="handleNoHideKeyboard" @keyboardShow="handleKeyboardShow" @keyboardHide="handleKeyboardHide" />
    </div>
  </div>
</template>

<script setup>
import { computed, onMounted, nextTick, onUnmounted, ref } from "vue";
import { showToast } from "vant";
import { useI18n } from "vue-i18n";
import { emitter } from "@/utils/events";
import {
  MessageRole,
  MessageType,
  CompName,
  Command,
} from "@/constants/ChatModel";
import WebSocketManager from "@/utils/WebSocketManager";
import {
  SWITCH_TO_COMPANION_TAB,
  SWITCH_TO_DISCOVERY_TAB,
  SCROLL_TO_BOTTOM,
  SEND_MESSAGE_CONTENT_TEXT,
  SEND_MESSAGE_COMMAND_TYPE,
  NOTICE_EVENT_LOGOUT,
  NOTICE_EVENT_LOGIN_SUCCESS,
} from "@/constants/constant";
import {
  mainPageData,
  conversationMsgList,
  recentConversation,
} from "@/api/home";
import { IdUtils } from "@/utils/IdUtils";
import { resolveChatSocketUrl } from "@/utils/socketUrl";
import {
  appendLongTextChunk,
  createLongTextData,
} from "@/constants/longTextCard";
import { checkToken } from "@/hooks/useGoLogin";
import { ensureValidAuthToken } from "@/utils/request";
import { useAppStore } from "@/store";
import { getAccessToken } from "@/constants/token";
import Welcome from "../Welcome/index.vue";
import AiTabSwitch from "../AiTabSwitch/index.vue";
import Discovery from "../Discovery/index.vue";
import ChatGuide from "../ChatGuide/index.vue";
import AigcPhotoCard from "../AigcPhotoCard/index.vue";
import ChatTopNavBar from "../ChatTopNavBar/index.vue";
import ChatCardAI from "../ChatCardAi/index.vue";
import ChatCardMine from "../ChatCardMine/index.vue";
import ChatCardOther from "../ChatCardOther/index.vue";
import ChatQuickAccess from "../ChatQuickAccess/index.vue";
import ChatInputArea from "../ChatInputArea/index.vue";
import QuickBookingComponent from "../QuickBookingComponent/index.vue";
import DiscoveryCardComponent from "../DiscoveryCardComponent/index.vue";
import ActivityListComponent from "../ActivityListComponent/index.vue";
import RecommendPostsComponent from "../RecommendPostsComponent/index.vue";
import AttachListComponent from "../AttachListComponent/index.vue";
import DetailCardComponent from "../DetailCardComponent/index.vue";
import OpenMapComponent from "../OpenMapComponent/index.vue";
import AnswerComponent from "../AnswerComponent/index.vue";
import GeneratorPhotoComponent from "../GeneratorPhotoComponent/index.vue";
import LongTextGuideCardPreview from "../LongTextGuideCardPreview/index.vue";
import CreateServiceOrder from "../CreateServiceOrder/index.vue";
import Feedback from "../Feedback/index.vue";
import AddCarCard from "../AddCarCard/index.vue";
import SurveyQuestionnaire from "../SurveyQuestionnaire/index.vue";

const emit = defineEmits(["showDrawer"]);
const appStore = useAppStore();
const { t } = useI18n();

/// 输入框组件引用
const inputAreaRef = ref(null);
const mainScrollRef = ref(null);
const topNavBarRef = ref();
const noticeContent = ref(null);

const holdKeyboardTimer = ref(null);
/// focus时，点击页面的时候不收起键盘
const holdKeyboard = ref(false);
/// 是否在键盘弹出，点击界面时关闭键盘
const holdKeyboardFlag = ref(true);
/// 是否显示键盘
const isKeyboardShow = ref(false);

///（控制滚动位置）
const scrollTop = ref(99999);

/// 会话列表
const chatMsgList = ref([]);
/// 输入框的输入消息
const inputMessage = ref("");

/// 是否自动滚动到底部 (人工手动向上滚动时设为false)
const isAutoScroll = ref(true);
let lastHideKeyboardAt = 0;
let lastScrollTouchAt = 0;

/// agentId 首页接口中获取
const agentId = ref("1");
/// 会话ID 历史数据接口中获取
const conversationId = ref("");
/// 首页的数据
const mainPageDataModel = ref({});

// 会话进行中标志
const isSessionActive = ref(false);
/// 指令
let messageCommonType = "";

// WebSocket 相关
let webSocketManager = null;
/// 使用统一的连接状态判断函数，避免状态不同步
const isWsConnected = () =>
  !!(
    webSocketManager &&
    typeof webSocketManager.isConnected === "function" &&
    webSocketManager.isConnected()
  );

// pendingMap: messageId -> msgIndex
const pendingMap = new Map();
// pendingTimeouts: messageId -> timeoutId
const pendingTimeouts = new Map();
// 超时时间（ms）
const MESSAGE_TIMEOUT = 30000;

// 防止并发初始化 websocket
let isInitializing = false;
let pendingInitPromise = null;
// sleep helper
const sleep = (ms) => new Promise((res) => setTimeout(res, ms));

// 当前会话的消息ID，用于保持发送和终止的messageId一致
let currentSessionMessageId = null;

const tabIndex = ref(0);
const tabList = computed(() => [
  t("home.chat.discovery"),
  t("home.chat.aiTour"),
]);

const handleChange = (i) => {
  console.log("🚀 ~ handleChange ~ i:", i)
  tabIndex.value = i;
};

/// =============事件函数↓================
const handleTouchEnd = () => {
  clearTimeout(holdKeyboardTimer.value);
  holdKeyboardTimer.value = setTimeout(() => {
    // 键盘弹出时点击界面则关闭键盘
    if (holdKeyboardFlag.value && isKeyboardShow.value) {
      // uni.hideKeyboard();
    }
    holdKeyboardFlag.value = true;
  }, 100);
};

// 点击输入框、发送按钮时，不收键盘
const handleNoHideKeyboard = () => (holdKeyboardFlag.value = false);

// 键盘弹起事件
const handleKeyboardShow = () => {
  isKeyboardShow.value = true;
  holdKeyboard.value = true;
  // 键盘弹起时调整聊天内容的底部边距并滚动到底部
  setTimeout(() => {
    scrollToBottom(true);
  }, 150);
};

// 键盘收起事件
const handleKeyboardHide = () => {
  isKeyboardShow.value = false;
  holdKeyboard.value = false;
};

const hideKeyboardByScroll = () => {
  const now = Date.now();
  if (now - lastHideKeyboardAt < 300) return;
  lastHideKeyboardAt = now;

  holdKeyboard.value = false;
  holdKeyboardFlag.value = true;
  isKeyboardShow.value = false;

  if (
    inputAreaRef.value &&
    typeof inputAreaRef.value.blurInput === "function"
  ) {
    inputAreaRef.value.blurInput();
  }
};

const hideKeyboardAfterSend = () => {
  holdKeyboard.value = false;
  holdKeyboardFlag.value = true;
  isKeyboardShow.value = false;

  if (
    inputAreaRef.value &&
    typeof inputAreaRef.value.blurInput === "function"
  ) {
    inputAreaRef.value.blurInput();
  }
};

const handleScrollAreaTouchStart = () => {
  lastScrollTouchAt = Date.now();
  hideKeyboardByScroll();
};

const handleScrollAreaTouchMove = () => {
  lastScrollTouchAt = Date.now();
  hideKeyboardByScroll();
};

// 处理用户滚动事件
const welcomeHeight = ref(252);
const isHeaderCollapsed = ref(false);
let lastScrollTop = 0;
const handleScroll = (e) => {
  if (Date.now() - lastScrollTouchAt < 1000) {
    hideKeyboardByScroll();
  }

  const currentScrollTop = Number(
    e?.detail?.scrollTop ?? e?.target?.scrollTop ?? 0,
  );
  const scrollEl = e?.target;

  // 滚动回顶部时还原头部布局
  if (currentScrollTop <= 0 && isHeaderCollapsed.value) {
    isHeaderCollapsed.value = false;
  }

  // 向上滚动超过头部高度时收敛
  if (currentScrollTop > welcomeHeight.value && !isHeaderCollapsed.value) {
    isHeaderCollapsed.value = true;
  }

  if (topNavBarRef.value) {
    topNavBarRef.value.show = currentScrollTop > welcomeHeight.value;
  }
  if (
    scrollEl &&
    scrollEl.scrollHeight - currentScrollTop - scrollEl.clientHeight < 8
  ) {
    isAutoScroll.value = true;
  }
  // 如果向上滚动 (当前位置小于上一次记录的位置)
  if (currentScrollTop < lastScrollTop - 2) {
    // 增加 2px 阈值防止抖动
    isAutoScroll.value = false;
  }
  lastScrollTop = currentScrollTop;
};

// 处理滚动到底部事件
const handleScrollToLower = () => {
  // 当用户滚动到底部时，明确开启自动滚动
  isAutoScroll.value = true;
};

// 滚动到底部 - 优化版本，确保打字机效果始终可见
const scrollToBottom = (force = false) => {
  // 如果当前不是自动滚动模式且非强制触发，则不执行滚动
  if (!isAutoScroll.value && !force) {
    console.log("暂停自动滚动，当前位置:", scrollTop.value);
    return;
  }

  nextTick(() => {
    // 使用更大的值确保滚动到真正的底部
    const targetScrollTop = 99999 + Math.random();
    scrollTop.value = targetScrollTop;
    if (
      mainScrollRef.value &&
      typeof mainScrollRef.value.scrollTo === "function"
    ) {
      mainScrollRef.value.scrollTo({
        top: mainScrollRef.value.scrollHeight,
        behavior: "smooth",
      });
    }
  });
};

// 延时滚动
const setTimeoutScrollToBottom = (force = false) =>
  setTimeout(() => scrollToBottom(force), 100);

// 发送普通消息
const handleReplyText = (text) => {
  // 发送消息时，强制开启自动滚动
  isAutoScroll.value = true;
  // 重置消息状态，准备接收新的AI回复
  resetMessageState();
  sendMessage(text);
  setTimeoutScrollToBottom(true);
};

// 是发送指令消息
const handleReplyInstruct = async (item) => {
  await checkToken();

  // 发送消息时，强制开启自动滚动
  isAutoScroll.value = true;
  messageCommonType = item.type;
  // 重置消息状态，准备接收新的AI回复
  resetMessageState();
  sendMessage(item.title, true);
  setTimeoutScrollToBottom(true);
};

//  输入区的发送消息事件
const sendMessageAction = (inputText) => {
  console.log("输入消息:", inputText);
  if (!inputText.trim()) return;

  // 发送消息时，强制开启自动滚动
  isAutoScroll.value = true;
  // 重置消息状态，准备接收新的AI回复
  resetMessageState();

  sendMessage(inputText);
  hideKeyboardAfterSend();

  setTimeoutScrollToBottom(true);
};

/// 添加通知
const addNoticeListener = () => {
  // emitter.on(NOTICE_EVENT_LOGIN_SUCCESS, () => {
  //   if (!isWsConnected()) {
  //     initHandler();
  //   }
  // });

  // emitter.on(NOTICE_EVENT_LOGOUT, () => {
  //   resetConfig();
  // });

  // emitter.on(SCROLL_TO_BOTTOM, () => {
  //   setTimeout(() => {
  //     scrollToBottom(true);
  //   }, 200);
  // });

  emitter.on(SEND_MESSAGE_CONTENT_TEXT, (value) => {
    console.log("SEND_MESSAGE_CONTENT_TEXT:", value);
    if (value && value.length) {
      handleReplyText(value);
    }
  });

  emitter.on(SEND_MESSAGE_COMMAND_TYPE, (item) => {
    console.log("SEND_MESSAGE_COMMAND_TYPE:", item);
    if (item && item.type) {
      handleReplyInstruct(item);
    }
  });

  emitter.on(SWITCH_TO_COMPANION_TAB, () => {
    tabIndex.value = 1;
  });

  emitter.on(SWITCH_TO_DISCOVERY_TAB, () => {
    tabIndex.value = 0;
  });
};

// token存在，初始化数据
const initHandler = async () => {
  console.log("initHandler");
  const token = await ensureValidAuthToken().catch(() => null);

  if (!token) return;
  loadRecentConversation();
  ///loadConversationMsgList();
  initWebSocket();
};

onMounted(() => {
  console.log("onMounted");
  getMainPageData();
  addNoticeListener();
  // 有token时，加载最近会话、最近消息、初始化socket
  initHandler();
});

/// =============页面配置↓================
// 获取最近一次的会话id
const loadRecentConversation = async () => {
  const res = await recentConversation();
  if (res.code === 0) {
    conversationId.value = res.data.conversationId;
  }
};

// 加载历史消息的数据
let historyCurrentPageNum = 1;
const loadConversationMsgList = async () => {
  const args = {
    pageNum: historyCurrentPageNum++,
    pageSize: 10,
    conversationId: conversationId.value,
  };
  const res = await conversationMsgList(args);
};

// 获取首页数据

const getMainPageData = async () => {
  // 从个渠道获取如二维，没有的时候就返回首页的数据
  const sceneId = appStore.sceneId || "";
  const res = await mainPageData({ sceneId });
  console.log("🚀 ~ getMainPageData ~ res:", res);

  if (res.code === 0) {
    initData();
    mainPageDataModel.value = res.data;
    agentId.value = res.data.agentId;
  }

  appStore.setSceneId(""); // 清空sceneId,分身二次进入展示默认的
};

/// =============对话↓================
// 初始化WebSocket
const initWebSocket = async () => {
  // 防止并发初始化
  if (isInitializing) {
    return pendingInitPromise;
  }

  isInitializing = true;
  pendingInitPromise = (async () => {
    // 清理旧实例
    if (webSocketManager) {
      try {
        webSocketManager.destroy();
      } catch (e) {
        console.warn("destroy old webSocketManager failed:", e);
      }
      webSocketManager = null;
    }

    // 使用配置的WebSocket服务器地址
    const token = getAccessToken();
    if (!token) {
      isInitializing = false;
      pendingInitPromise = null;
      return false;
    }
    const resolvedWsUrl = resolveChatSocketUrl(appStore.serverConfig.wssUrl);
    const wsUrl = `${resolvedWsUrl}?access_token=${token}`;

    // 初始化WebSocket管理器
    webSocketManager = new WebSocketManager({
      wsUrl: wsUrl,
      reconnectInterval: 3000, // 重连间隔
      maxReconnectAttempts: 5, // 最大重连次数
      heartbeatInterval: 30000, // 心跳间隔

      // 连接成功回调
      onOpen: (event) => {
        console.log("WebSocket连接成功");
        // 重置会话状态
        isSessionActive.value = false; // 连接成功时重置会话状态，避免影响新消息发送

        // 连接成功后发送 welcome 消息 (messageType=4)
        try {
          // fire-and-forget, sendWebSocketMessage 会处理重连与队列
          sendWebSocketMessage(MessageType.notice, Command.messageInit, {
            tryReconnect: true,
            messageId: IdUtils.generateMessageId(),
          }).catch((e) => {
            console.warn("发送 Command.messageInit 消息失败:", e);
          });
        } catch (e) {
          console.warn("发送 Command.messageInit 消息时异常:", e);
        }
      },

      // 连接断开回调
      onClose: (event) => {
        console.error("WebSocket连接断开:", event);
        // 停止当前会话
        isSessionActive.value = false;
      },

      // 错误回调
      onError: (error) => {
        console.error("WebSocket错误:", error);
        isSessionActive.value = false;
      },

      // 消息回调
      onMessage: (data) => {
        handleWebSocketMessage(data);
      },

      // 获取会话ID回调 (用于心跳检测)
      getConversationId: () => conversationId.value,

      // 获取代理ID回调 (用于心跳检测)
      getAgentId: () => agentId.value,
    });

    try {
      // 初始化连接
      await webSocketManager.connect();
      console.log("WebSocket连接初始化成功");
      return true;
    } catch (error) {
      console.error("WebSocket连接失败:", error);
      return false;
    } finally {
      isInitializing = false;
      pendingInitPromise = null;
    }
  })();

  return pendingInitPromise;
};

// 处理WebSocket消息
const handleWebSocketMessage = (data) => {
  // 验证关键字段（若服务端传回 conversationId/agentId，则校验是否属于当前会话）
  if (data.conversationId && data.conversationId !== conversationId.value) {
    console.warn("收到不属于当前会话的消息，忽略", data.conversationId);
    return;
  }
  if (data.agentId && data.agentId !== agentId.value) {
    console.warn("收到不属于当前 agent 的消息，忽略", data.agentId);
    return;
  }

  if (data.messageType && data.messageType === "broadcast") {
    console.log("收到 welcome 类型消息:", data);
    if (data.content) {
      noticeContent.value = data.content;
    }
    return;
  }

  let aiMsgIndex = -1;
  // Prefer matching by replyMessageId if provided
  if (data.replyMessageId) {
    // 1) Try to find an existing AI message that already has the same replyMessageId
    for (let i = chatMsgList.value.length - 1; i >= 0; i--) {
      const it = chatMsgList.value[i];
      if (
        it &&
        it.msgType === MessageRole.AI &&
        it.replyMessageId === data.replyMessageId
      ) {
        aiMsgIndex = i;
        break;
      }
    }

    // 2) If not found, check pendingMap for currentSessionMessageId
    if (
      aiMsgIndex === -1 &&
      currentSessionMessageId &&
      pendingMap.has(currentSessionMessageId)
    ) {
      const idx = pendingMap.get(currentSessionMessageId);
      if (idx >= 0 && idx < chatMsgList.value.length) {
        const item = chatMsgList.value[idx];
        // If the pending item already has a different non-empty replyMessageId, create a new AI entry
        if (
          item &&
          item.msgType === MessageRole.AI &&
          item.replyMessageId &&
          item.replyMessageId !== data.replyMessageId
        ) {
          const aiMsg = {
            msgId: `msg_${chatMsgList.value.length}`,
            msgType: MessageRole.AI,
            msg: "",
            isLoading: false,
            messageId: currentSessionMessageId,
            replyMessageId: data.replyMessageId || "",
            componentName: "",
            longTextData: null,
            finish: false,
          };
          chatMsgList.value.push(aiMsg);
          aiMsgIndex = chatMsgList.value.length - 1;
        } else {
          // Reuse the pending item
          aiMsgIndex = idx;
        }
      }
    }

    // 3) If still not found, create a new AI message for this replyMessageId
    if (aiMsgIndex === -1) {
      const aiMsg = {
        msgId: `msg_${chatMsgList.value.length}`,
        msgType: MessageRole.AI,
        msg: "",
        isLoading: false,
        messageId: currentSessionMessageId,
        replyMessageId: data.replyMessageId || "",
        componentName: "",
        longTextData: null,
        finish: false,
      };
      chatMsgList.value.push(aiMsg);
      aiMsgIndex = chatMsgList.value.length - 1;
    }
  } else {
    // No replyMessageId: fall back to most recent AI message
    for (let i = chatMsgList.value.length - 1; i >= 0; i--) {
      if (
        chatMsgList.value[i] &&
        chatMsgList.value[i].msgType === MessageRole.AI
      ) {
        aiMsgIndex = i;
        break;
      }
    }
    if (aiMsgIndex === -1) {
      console.error("处理WebSocket消息时找不到对应的AI消息项");
      return;
    }
  }

  // 防护：确保 aiMsgIndex 有效
  if (aiMsgIndex < 0 || aiMsgIndex >= chatMsgList.value.length) {
    console.error("无效的 aiMsgIndex:", aiMsgIndex);
    return;
  }

  // replyMessageId
  if (data.replyMessageId) {
    chatMsgList.value[aiMsgIndex].replyMessageId = data.replyMessageId;
  }

  // 如果服务端在分片中就带来了 componentName，提前记录并将已缓存的 msg 转移到 componentMsg
  const aiItem = chatMsgList.value[aiMsgIndex];
  if (data.componentName) {
    aiItem.componentName = data.componentName;
    if (isLongTextCard(data.componentName)) {
      aiItem.longTextData = aiItem.longTextData || createLongTextData();
      if (aiItem.msg && aiItem.msg.length > 0) {
        if (!aiItem.isLoading) {
          aiItem.componentMsg = (aiItem.componentMsg || "") + aiItem.msg;
        }
        aiItem.msg = "";
      }
    }
  }

  const isLongText =
    isLongTextCard(aiItem.componentName) || isLongTextCard(data.componentName);

  if (isLongText && data.contentKey) {
    aiItem.longTextData = aiItem.longTextData || createLongTextData();
    appendLongTextChunk(aiItem.longTextData, data);
    if (aiItem.isLoading) {
      aiItem.msg = "";
      aiItem.isLoading = false;
    }
    nextTick(() => scrollToBottom());
  }

  // 确保消息内容是字符串类型
  if (data.content && typeof data.content !== "string") {
    try {
      data.content = JSON.stringify(data.content);
    } catch (e) {
      data.content = String(data.content);
    }
  }

  // 直接拼接内容到对应 AI 消息
  if (data.content) {
    // 如果该条消息属于 longTextCard，使用 componentMsg 存储内容并保持 ChatCardAI 的 text 为空
    if (isLongText) {
      if (aiItem.isLoading) {
        aiItem.componentMsg = (aiItem.componentMsg || "") + data.content;
        aiItem.isLoading = false;
      } else {
        aiItem.componentMsg = (aiItem.componentMsg || "") + data.content;
      }
    } else {
      if (aiItem.isLoading) {
        // 首次收到内容：替换“加载中”文案并取消 loading 状态（恢复原始渲染逻辑）
        aiItem.msg = data.content;
        aiItem.isLoading = false;
      } else {
        // 后续流式内容追加
        aiItem.msg += data.content;
      }
    }
    nextTick(() => scrollToBottom());
  }

  // 处理完成状态
  if (data.finish) {
    chatMsgList.value[aiMsgIndex].finish = true;
    const msg = chatMsgList.value[aiMsgIndex].msg;
    if (!msg || chatMsgList.value[aiMsgIndex].isLoading) {
      // 如果服务器返回了 componentName 或 toolCall，应保留空消息以供组件渲染；否则显示错误占位
      if (data.toolCall || data.componentName) {
        chatMsgList.value[aiMsgIndex].msg = "";
      } else {
        chatMsgList.value[aiMsgIndex].msg = t("home.chat.emptyReply");
      }
      chatMsgList.value[aiMsgIndex].isLoading = false;
    }

    // 处理组件调用
    if (data.componentName) {
      chatMsgList.value[aiMsgIndex].componentName = data.componentName;
    }

    // 处理toolCall
    if (data.toolCall) {
      chatMsgList.value[aiMsgIndex].toolCall = data.toolCall;
    }

    // 处理question
    if (data.question && data.question.length > 0) {
      chatMsgList.value[aiMsgIndex].question = data.question;
    }

    // 清理 pendingMap / timeout
    const ownedMessageId = chatMsgList.value[aiMsgIndex].messageId || null;
    if (ownedMessageId) {
      if (pendingTimeouts.has(ownedMessageId)) {
        clearTimeout(pendingTimeouts.get(ownedMessageId));
        pendingTimeouts.delete(ownedMessageId);
      }
      pendingMap.delete(ownedMessageId);
    }

    // 重置会话状态
    isSessionActive.value = false;
    // 清理当前会话的 messageId，避免保留陈旧 id
    resetMessageState();

    nextTick(() => scrollToBottom());
    console.log("消息接收完成:", JSON.stringify(chatMsgList.value[aiMsgIndex]));
  }
};

const isLongTextCard = (componentName) => {
  return (
    componentName === CompName.longTextCard ||
    componentName === CompName.longTextCardSnap ||
    componentName === CompName.longTextCardRoute ||
    componentName === CompName.longTextCardScenicSpot
  );
};

// 重置消息状态
const resetMessageState = () => {
  // 重置当前会话消息ID
  currentSessionMessageId = null;
};

// 初始化数据 首次数据加载的时候
const initData = () => {
  const msg = {
    msgId: `msg_${0}`,
    msgType: MessageRole.OTHER,
    msg: "",
  };
  chatMsgList.value.push(msg);
};

// 发送消息的参数拼接
const sendMessage = async (message, isInstruct = false) => {
  console.log("发送的消息：", message);

  await checkToken();

  /// 切换到对话tab
  if (tabIndex.value !== 1) {
    tabIndex.value = 1;
  }

  // 发起对话时收敛头部
  isHeaderCollapsed.value = true;

  // 检查WebSocket连接状态，如果未连接，尝试重新连接
  if (!isWsConnected()) {
    console.log("WebSocket未连接，尝试重新连接...");
    // 显示加载提示
    // uni.showLoading({
    //   title: "正在连接服务器...",
    // });

    // 尝试重新初始化WebSocket连接
    try {
      await initWebSocket();
      // 等待短暂时间确保连接建立
      await new Promise((resolve) => setTimeout(resolve, 1000));

      // 检查连接是否成功建立
      if (!isWsConnected()) {
        // uni.hideLoading();
        setTimeout(() => {
          showToast(t("home.chat.connectionFailed"));
        }, 100);
        return;
      }
      // uni.hideLoading();
    } catch (error) {
      console.error("重新连接WebSocket失败:", error);
      // uni.hideLoading();
      setTimeout(() => {
        showToast(t("home.chat.connectionFailed"));
      }, 100);
      return;
    }
  }

  if (isSessionActive.value) {
    showToast(t("home.chat.waitCurrentReply"));
    return;
  }
  isSessionActive.value = true;
  const newMsg = {
    msgId: `msg_${chatMsgList.value.length}`,
    msgType: MessageRole.ME,
    msg: message,
  };
  chatMsgList.value.push(newMsg);
  inputMessage.value = "";
  // 发送消息后滚动到底部
  setTimeoutScrollToBottom(true);
  sendChat(message, isInstruct);
  console.log("发送的新消息：", JSON.stringify(newMsg));
};

// 通用WebSocket消息发送函数 -> 返回 Promise<boolean>
const sendWebSocketMessage = async (
  messageType,
  messageContent,
  options = {},
) => {
  const args = {
    conversationId: conversationId.value,
    agentId: agentId.value,
    messageType: String(messageType), // 消息类型 0-对话 1-指令 2-中断停止 3-心跳检测 4-消息
    messageContent: messageContent,
    messageId: options.messageId || currentSessionMessageId,
  };

  const maxRetries = typeof options.retries === "number" ? options.retries : 3;
  const baseDelay =
    typeof options.baseDelay === "number" ? options.baseDelay : 300; // ms
  const maxDelay =
    typeof options.maxDelay === "number" ? options.maxDelay : 5000; // ms

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    // 确保连接
    if (!isWsConnected()) {
      if (options.tryReconnect) {
        try {
          await initWebSocket();
        } catch (e) {
          console.error("reconnect failed in sendWebSocketMessage:", e);
        }
      }
    }

    if (!isWsConnected()) {
      if (!options.silent) console.warn("WebSocket 未连接，无法发送消息", args);
      // 如果还有重试机会，进行等待后重试
      if (attempt < maxRetries) {
        const delay = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
        await sleep(delay);
        continue;
      }
      isSessionActive.value = false;
      return false;
    }

    try {
      const raw = webSocketManager.sendMessage(args);
      // 兼容可能返回同步布尔或 Promise 的实现
      const result = await Promise.resolve(raw);
      if (result) {
        console.log(`WebSocket消息已发送 [类型:${messageType}]:`, args);
        return true;
      }

      // 若返回 false，消息可能已经被 manager 入队并触发连接流程。
      // 在这种情况下避免立即当作失败处理，而是等待短暂时间以观察连接是否建立并由 manager 发送队列。
      console.warn(
        "webSocketManager.sendMessage 返回 false，等待连接或队列发送...",
        { attempt, args },
      );
      const waitForConnectMs =
        typeof options.waitForConnectMs === "number"
          ? options.waitForConnectMs
          : 5000;
      if (
        webSocketManager &&
        typeof webSocketManager.isConnected === "function" &&
        !webSocketManager.isConnected()
      ) {
        const startTs = Date.now();
        while (Date.now() - startTs < waitForConnectMs) {
          await sleep(200);
          if (webSocketManager.isConnected()) {
            // 给 manager 一点时间处理队列并发送
            await sleep(150);
            console.log("检测到 manager 已连接，假定队列消息已发送", args);
            return true;
          }
        }
        console.warn("等待 manager 建连超时，进入重试逻辑", {
          waitForConnectMs,
          args,
        });
      } else {
        console.warn(
          "sendMessage 返回 false 但 manager 看起来已连接或不可用，继续重试",
          { args },
        );
      }
    } catch (error) {
      console.error("发送WebSocket消息异常:", error, args);
    }

    // 失败且还有重试机会，等待指数退避
    if (attempt < maxRetries) {
      const delay = Math.min(maxDelay, baseDelay * Math.pow(2, attempt));
      await sleep(delay + Math.floor(Math.random() * 100));
      continue;
    }

    // 最后一次失败
    isSessionActive.value = false;
    return false;
  }
  // 不可达，但为了类型安全
  isSessionActive.value = false;
  return false;
};

// 发送获取AI聊天消息
const sendChat = async (message, isInstruct = false) => {
  // 检查WebSocket管理器是否存在，如果不存在，尝试重新初始化
  if (!webSocketManager) {
    console.error("WebSocket管理器不存在，尝试重新初始化...");
    initWebSocket();
    // 短暂延迟后再次检查连接状态
    setTimeout(() => {
      const connected = webSocketManager && webSocketManager.isConnected();
      isSessionActive.value = connected;
      // 更新AI消息状态
      const aiMsgIndex = chatMsgList.value.length - 1;
      if (
        aiMsgIndex >= 0 &&
        chatMsgList.value[aiMsgIndex].msgType === MessageRole.AI
      ) {
        chatMsgList.value[aiMsgIndex].msg = connected
          ? ""
          : t("home.chat.sendFailed");
        chatMsgList.value[aiMsgIndex].isLoading = connected;
      }
      if (connected) {
        // 连接成功后重新发送消息
        sendChat(message, isInstruct);
      } else {
        console.error("WebSocket重新初始化失败");
      }
    }, 1000);
    return;
  }

  const messageType = isInstruct ? MessageType.command : MessageType.dialog;
  const messageContent = isInstruct ? messageCommonType : message;
  // 生成 messageId 并保存到当前会话变量（stopRequest 可能使用）
  currentSessionMessageId = IdUtils.generateMessageId();

  // 插入AI消息，并在 pendingMap 中记录
  const aiMsg = {
    msgId: `msg_${chatMsgList.value.length}`,
    msgType: MessageRole.AI,
    msg: t("home.chat.pending"),
    isLoading: true,
    messageId: currentSessionMessageId,
    replyMessageId: "",
    componentName: "",
    longTextData: null,
    finish: false,
  };
  chatMsgList.value.push(aiMsg);
  // 添加AI消息后滚动到底部
  setTimeoutScrollToBottom(true);
  const aiMsgIndex = chatMsgList.value.length - 1;

  // 记录 pendingMap
  pendingMap.set(currentSessionMessageId, aiMsgIndex);

  // 启动超时回退
  const timeoutId = setTimeout(() => {
    const idx = pendingMap.get(currentSessionMessageId);
    if (
      idx != null &&
      chatMsgList.value[idx] &&
      chatMsgList.value[idx].isLoading
    ) {
      chatMsgList.value[idx].msg = t("home.chat.requestTimeout");
      chatMsgList.value[idx].isLoading = false;
      pendingMap.delete(currentSessionMessageId);
      pendingTimeouts.delete(currentSessionMessageId);
      isSessionActive.value = false;
      setTimeoutScrollToBottom(true);
    }
  }, MESSAGE_TIMEOUT);
  pendingTimeouts.set(currentSessionMessageId, timeoutId);

  // 发送消息，支持重连尝试
  const success = await sendWebSocketMessage(messageType, messageContent, {
    messageId: currentSessionMessageId,
    tryReconnect: true,
  });
  if (!success) {
    const idx = pendingMap.get(currentSessionMessageId);
    if (idx != null && chatMsgList.value[idx]) {
      chatMsgList.value[idx].msg = t("home.chat.sendFailed");
      chatMsgList.value[idx].isLoading = false;
    }
    // 清理 pending
    if (pendingTimeouts.has(currentSessionMessageId)) {
      clearTimeout(pendingTimeouts.get(currentSessionMessageId));
      pendingTimeouts.delete(currentSessionMessageId);
    }
    pendingMap.delete(currentSessionMessageId);
    isSessionActive.value = false;
  }
};

// 停止请求函数
const stopRequest = async () => {
  console.log("停止请求");

  // 发送中断消息给服务器 (messageType=2)，带上当前 messageId
  try {
    await sendWebSocketMessage(MessageType.stop, "stop_request", {
      messageId: currentSessionMessageId,
      silent: true,
    });
  } catch (e) {
    console.warn("stopRequest send failed:", e);
  }

  // 直接将AI消息状态设为停止（优先使用 pendingMap 映射）
  let aiMsgIndex = -1;
  if (currentSessionMessageId && pendingMap.has(currentSessionMessageId)) {
    aiMsgIndex = pendingMap.get(currentSessionMessageId);
  } else {
    aiMsgIndex = chatMsgList.value.length - 1;
  }

  if (
    chatMsgList.value[aiMsgIndex] &&
    chatMsgList.value[aiMsgIndex].msgType === MessageRole.AI
  ) {
    chatMsgList.value[aiMsgIndex].isLoading = false;
    if (
      chatMsgList.value[aiMsgIndex].msg &&
      chatMsgList.value[aiMsgIndex].msg.trim() &&
      !chatMsgList.value[aiMsgIndex].msg.startsWith(t("home.chat.pending"))
    ) {
      // 保留已显示内容
    } else {
      chatMsgList.value[aiMsgIndex].msg = t("home.chat.requestStopped");
    }
  }

  // 清理 pending
  if (currentSessionMessageId) {
    if (pendingTimeouts.has(currentSessionMessageId)) {
      clearTimeout(pendingTimeouts.get(currentSessionMessageId));
      pendingTimeouts.delete(currentSessionMessageId);
    }
    pendingMap.delete(currentSessionMessageId);
  }

  // 重置会话状态
  isSessionActive.value = false;
  setTimeoutScrollToBottom(true);
};

// 组件销毁时清理资源
onUnmounted(() => {
  // uni.$off(NOTICE_EVENT_LOGIN_SUCCESS);
  // uni.$off(SCROLL_TO_BOTTOM);
  // uni.$off(SEND_MESSAGE_CONTENT_TEXT);
  // uni.$off(SEND_MESSAGE_COMMAND_TYPE);
  // uni.$off(NOTICE_EVENT_LOGOUT);

  resetConfig();
});

const resetConfig = () => {
  // 清理WebSocket连接
  if (webSocketManager) {
    webSocketManager.destroy();
    webSocketManager = null;
  }

  // 重置消息状态
  resetMessageState();
  isSessionActive.value = false;

  // 清理 pendingMap / pendingTimeouts
  try {
    for (const t of pendingTimeouts.values()) {
      clearTimeout(t);
    }
  } catch (e) {
    // ignore
  }
  pendingTimeouts.clear();
  pendingMap.clear();

  // 清理定时器
  if (holdKeyboardTimer.value) {
    clearTimeout(holdKeyboardTimer.value);
    holdKeyboardTimer.value = null;
  }
};
</script>
