<template>
  <view class="chat-container"  :style="{ 
    paddingTop: appStore.navbarHeight + 'px',
  }">
		<view class="mine_ybt_title flex-center bg_color_fff" 
		:style="{ height: appStore.navbarHeight + 'px',
    paddingTop: appStore.statusBarHeight + 'px'}"
		>
			<!-- <text class="font_size35 bold">AI客服</text> -->
     <agentCheck ref="agentCheckRef"></agentCheck>
		</view>
    <!-- 聊天消息区域 -->
    <view class="chat-messages flex-column">
			<!-- 工具栏 -->
			<tools @addHuiHuaFn="addHuiHuaFn"></tools>
			<!-- 消息列表 -->
      <scroll-view
        class="scrollViewRef flex_1"
        scroll-y="true" 
        :scroll-top="scrollTop"
        ref="scrollViewRef"
        :scroll-with-animation="true"
        @refresherrefresh="handlePullDownRefresh"
        :refresher-enabled="true"
        :refresher-triggered="triggered"
      >
        <messagesInfoDefault v-if="messages.length==0" 
        @sendMessage="sendMessage"
        ref="messagesInfoDefaultRef" key="messagesInfoDefaultRef">
        </messagesInfoDefault>
        <messagesInfo 
        :messages="messages" 
        :isLoading="isLoading" 
        @imageLoaded="scrollToBottom"
        :id="`msg-${messagesKey}`">
        </messagesInfo>
      </scroll-view>
    </view>
    <!-- 输入区域 -->
    <view class="input-area">
      <button class="image-btn" :disabled="isLoading" @click.stop.prevent="uploadImage">
        <image class="image-icon" src="/static/img/service/tupian.png" model="aspectFit"></image>
      </button>
      <button v-if="isvoice"
        class="record-btn"
        :class="{ recording: isRecording }"
        @touchstart="startRecord"
        @touchend="stopRecord"
        @touchmove="handleTouchMove"
        @touchcancel="cancelRecord"
        :disabled="isRecording && isCancel"
      >
        <view v-if="!isRecording">按住说话</view>
        <view v-if="isRecording && !isCancel">松手发送，上移取消</view>
        <view v-if="isRecording && isCancel">松手取消</view>
        <text v-if="recordDuration>0"></text>
      </button>
      <input v-else
        class="input-box"
        :placeholder="isLoading?'努力回答中...':'发消息或按住说话'"
        placeholder-style="color: #999"
        v-model.trim="inputText"
        :disabled="isLoading"
        @confirm="sendMessage({chatType:0,msgContent:inputText})"
      />
      <button class="isvoice-btn" @click.stop.prevent="isvoice=!isvoice;authorizeRecord()" :disabled="isLoading">
        <image class="mic-icon" src="/static/img/service/xiaoxi.png" v-if="isvoice" model="aspectFit"></image>
        <image class="mic-icon" src="/static/img/service/maikefengyuyin.png" v-else model="aspectFit"></image>
      </button>
      <button class="send-btn" @click.stop.prevent="sendMessage({chatType:0,msgContent:inputText})" :disabled="isLoading" v-if="!isvoice">
        <image class="send-icon" src="/static/img/service/send-icon.png"></image>
      </button>
      <view class="ai-tip">内容由AI生成，仅供参考</view>
    </view>
     <!-- 录音动画/提示 -->
      <view 
        class="record-toast" 
        v-if="isRecording"
        :class="{ cancel: isCancel }"
      >
        <image 
          v-if="!isCancel"
          src="/static/img/voice/recording.gif" 
          class="toast-icon"
          alt="录音中动画"
        ></image>
        <image 
          v-if="isCancel"
          src="/static/img/voice/cancel.png" 
          class="toast-icon"
          alt="取消录音图标"
        ></image>
        <text v-if="!isCancel">正在录音...({{60-recordDuration}})</text>
        <text v-if="isCancel">松手取消发送</text>
      </view>
  </view>
</template>

<script setup>
import { ref, nextTick, watch } from 'vue';
import { onShow,onHide,onLoad } from "@dcloudio/uni-app"
import { chatHistoryDetails } from '@/api/ai.js';
import messagesInfo from "./components/messagesInfo.vue";
import messagesInfoDefault from "./components/messagesInfoDefault.vue";
import tools from "./components/tools.vue";
import agentCheck from "./components/agentCheck.vue";
import {
	HTTP_REQUEST_URL,
	HTTP_REQUEST_URL_WS,
  TOKENNAME
} from '@/config/app';
import { chooseImageOne,checkLoginShowModal,checkAiQuotaDailyModal,getUserInfo } from "@/utils/util.js";
// 封装的websocket
import WSClient from '@/utils/wsUtil.js';
import { useAppStore } from '@/stores/app'
import { useToast } from '@/hooks/useToast'
import dayjs from "dayjs";
const appStore = useAppStore();
const { Toast } = useToast();
const agentCheckRef = ref(null);
const messagesInfoDefaultRef = ref(null);
const newSession = ref(false);//是否新会话
const historySession = ref('');//是否新会话

// 添加滚动相关变量
const scrollTimeout = ref(null);
const scrollViewRef = ref(null);
const scrollTop = ref(0);
const messagesKey = ref(0);
const triggered = ref(false);

// 底部发送功能
const inputText = ref('');
const isLoading = ref(false);//思考中
const isvoice = ref(false);//是否语音输入
const wsClient = ref(null);

// 模拟聊天消息数据
const messages = ref([]);

watch(() => appStore.agentId, (state) => {
  messages.value = [];
  getAdSearchFn()
});

onLoad((e)=>{
  console.log('ai onLoad',e);
})
onShow(async()=>{
  if(!await checkLoginShowModal())return;
  nextTick(async ()=>{
    // 初始化选择智能体
    await agentCheckRef.value.initAgentId();
     // 初始化完成后获取 agentId
    console.log('agentId:', agentCheckRef.value.agentId);
    if(appStore.msgContent){
      sendMessage({chatType:0,msgContent:appStore.msgContent});
      appStore.UPDATE_msgContent('');
    }else if(appStore.sessionId){
      handlePullDownRefresh();
    }else{
      // getAdSearchFn()
    }
    
  })

	aiStartChatFn();
});
onHide(()=>{
  isLoading.value = false;
  cleanupResources();
});
// 新增：添加回话功能
function addHuiHuaFn(){
  newSession.value = true;
  messages.value = [];
  getAdSearchFn();
}
function getAdSearchFn(){
  nextTick(()=>{
    setTimeout(()=>{
      messagesInfoDefaultRef.value.getAdSearchFn();
    },50)
  })
}

function authorizeRecord() { 
    uni.authorize({
    scope: 'scope.record',
    success() {
      // uni.getRecorderManager();
    }
  })
}
function aiStartChatFn(){ 
  cleanupResources();
  wsClient.value = new WSClient({
    url: `${HTTP_REQUEST_URL_WS}/api/websocket`,
    method: 'POST',
    headers: {
      "Authorization": 'Bearer '+appStore.token
    }
  });
  // 注册SSE事件
  registerEvents();
  wsClient.value.open({type:0,message:inputText.value})
}

// 
async function sendMessage({chatType,msgContent=""}){
  console.log('sendMessage',wsClient.value);
  // 登录检测
  if(!await checkLoginShowModal())return;
  // 今日免费提问次数检测
  if(!await checkAiQuotaDailyModal())return;
  if (!msgContent) {
    Toast({title:'请输入内容'});
    return;
  }
  isLoading.value = true
  messages.value.push({
    msgContent,
    chatType,// 0 (文本),1 (图片)
    speakerType:0//0用户消息1AI消息
  });
  messages.value.push({
    msgContent: "",
    event: "start",//sse长链接的返回状态
    chatType,
    speakerType:1,
    messageTimeNow:dayjs().format('HH:mm')
  });
  //type  0 (文本),1 (图片)
  wsClient.value.send({
    type:chatType,
    message:msgContent,
    agentId:agentCheckRef.value.agentId,
    useBalance:true,
    newSession:newSession.value,
    historySession:historySession.value
  });
  messagesKey.value++;
  inputText.value = '';
  newSession.value = false;
  // 每次收到新消息时滚动到底部
  // 如果是图片，子组件里图片加载成功后触发
  if(chatType!=1)scrollToBottom();
}
async function uploadImage(){
  if(!await checkLoginShowModal())return;
  const res = await chooseImageOne();
  console.log('uploadImage',res);
  if(res){
    // userInfo.value[key] = res.fileName
    sendMessage({chatType:1,msgContent:res.data})
  }
}
function cleanupResources(closeSSE=true) {
  // 关闭SSE连接
  if (wsClient.value) {
    // 移除所有事件监听
    if (wsClient.value.callbacks) {
      Object.keys(wsClient.value.callbacks).forEach(event => {
        wsClient.value.callbacks[event] = [];
      });
    }
    wsClient.value.close('clean');
    wsClient.value = null;
  }
}
function registerEvents(){
  wsClient.value.on('open', (data) => {
    console.log('ws连接成功',data);
  });
  wsClient.value.on('answer', (data) => {
    console.log('answer',data.segment,messages.value.length - 1);
    isLoading.value = false;
    const lastIndex = messages.value.length - 1;
    // 保存完整内容（累加片段）
    // const newFullAnswer = messages.value[lastIndex].msgContent + data.segment;
    messages.value[lastIndex].msgContent = messages.value[lastIndex].msgContent + data.segment;
    messagesKey.value++;
    console.log('answer',messages);
    // 每次收到新消息时滚动到底部
    scrollToBottom();
    nextTick(()=>{
      // 获取用户信息
      getUserInfo();
    })
  });
  wsClient.value.on('error', (err) => {
    isLoading.value = false;
    console.log('error',err);
    // aiStartChatFn();
    Toast({ title: JSON.stringify(err) || "服务器异常" });
  });
  wsClient.value.on('close', (data) => {
    isLoading.value = false;
    let lastIndex = messages.value.length - 1;
    console.log('close',data,lastIndex);
    // 判断关闭原因，取消，删除当前聊天内容，超时提示请求超时
    switch (data.reason) {
      case 'timeout': {
        // 提示超时
        // uni.showToast({
        //   title: '请求超时，请重试',
        //   icon: 'none'
        // });
        if(lastIndex>-1)messages.value[lastIndex].msgContent = messages.value[lastIndex].msgContent || "请求超时，请重试";
        aiStartChatFn();
        break;
      }
      default:
        break;
    }
  });
}

// 新增：滚动到底部的方法
function scrollToBottom() {
  nextTick(() => {
    // if (scrollTimeout.value) return;
    // scrollTimeout.value = setTimeout(() => {
      uni.createSelectorQuery()
      .select(`#msg-${messagesKey.value}`)
      .boundingClientRect(rect => {
        if (rect) {
          scrollTop.value = rect.height;
          // 使用更平滑的滚动方式
          uni.pageScrollTo({
            scrollTop: rect.bottom,
            duration: 100
          })
        }
      })
      .exec();
      // scrollTimeout.value = null;
    // }, 80); // 延长节流间隔至80ms，减少冲突
  });
}

/*******************************************历史数据********************************************************/ 

const hitstoryParams = ref({
  pageNum: 0,
  pageSize: 10,
  sessionId:appStore.sessionId,
});
// 重命名方法，避免与小程序生命周期冲突
function handlePullDownRefresh() {
  console.log('下拉刷新触发');
  triggered.value = true;
  hitstoryParams.value.pageNum++;
  chatHistoryDetailsFn();
}
function chatHistoryDetailsFn(){
  hitstoryParams.value.sessionId = appStore.sessionId;
  chatHistoryDetails(hitstoryParams.value).then(res=>{ 
    triggered.value = false;
    console.log('chatHistoryFn',res);
    const rows = res?.rows || [];
    if(rows.length==0 && hitstoryParams.value.pageNum>0){
      hitstoryParams.value.pageNum--;
      // Toast({title:'没有更多历史记录了'});
      return;
    }
    if(messages.value.length==res.total){
      Toast({title:'没有更多历史记录了'});
      return;
    }
    messages.value = [...rows, ...messages.value]
  })
}


/*******************************************语音功能********************************************************/ 

const isRecording = ref(false);// 是否正在录音
const isCancel = ref(false);         // 是否取消录音
const recordDuration = ref(0);       // 录音时长（秒）
const tempFilePath = ref('');        // 录音临时文件路径
const recordTimer = ref(null);       // 录音计时定时器
const recorderManager = uni.getRecorderManager();  // 录音管理
// 开始录音（触摸开始）
const startRecord = async (e) => {
  if(!await checkLoginShowModal())return;
  // 防止冒泡导致的异常
  e.stopPropagation();
  
  // 初始化录音参数
  const options = {
    format: 'mp3',       // 录音格式
    sampleRate: 44100,   // 采样率
    numberOfChannels: 1, // 声道数
    encodeBitRate: 96000 // 编码比特率
  };

  // 开始录音
  recorderManager.start(options);
  isRecording.value = true;
  isCancel.value = false;
  recordDuration.value = 0;

  // 计时逻辑
  recordTimer.value = setInterval(() => {
    recordDuration.value++;
    // 限制最大录音时长（如60秒）
    if (recordDuration.value >= 60) {
      stopRecord();
    }
  }, 1000);

  // 监听录音错误
  recorderManager.onError((err) => {
    console.error('录音错误:', err);
    cancelRecord();
    uni.showToast({ title: '录音失败', icon: 'none' });
  });
};

// 停止录音（触摸结束）
const stopRecord = () => {
  if (!isRecording.value) return;

  // 清除计时
  clearInterval(recordTimer.value);
  
  // 停止录音
  recorderManager.stop();
  recorderManager.onStop((res) => {
    tempFilePath.value = res.tempFilePath;
    console.log('recorderManager',res.tempFilePath);
    
    // 判断是否取消或录音过短
    if (isCancel.value) {
      uni.showToast({ title: '已取消发送', icon: 'none' });
    } else if (recordDuration.value < 1) {
      uni.showToast({ title: '录音时间太短', icon: 'none' });
    } else {
      // 上传录音并添加到列表
      uploadVoice(res.tempFilePath);
    }
    // 重置状态
    resetRecordState();
  });

 
};

// 处理触摸移动（用于判断是否取消）
const handleTouchMove = (e) => {
  if (!isRecording.value) return;

  // 获取按钮位置和触摸位置
  const buttonRect = uni.createSelectorQuery().select('.record-btn').boundingClientRect();
  buttonRect.exec((rects) => {
    const rect = rects[0];
    if (!rect) return;

    // 计算触摸点与按钮的垂直距离（向上移动超过50px视为取消）
    const touchY = e.touches[0].clientY;
    const buttonTop = rect.top;
    if (touchY < buttonTop - 50) {
      isCancel.value = true;
    } else {
      isCancel.value = false;
    }
  });
};

// 取消录音（触摸中断）
const cancelRecord = () => {
  if (!isRecording.value) return;
  
  clearInterval(recordTimer.value);
  recorderManager.stop();
  resetRecordState();
  uni.showToast({ title: '已取消发送', icon: 'none' });
};

// 重置录音状态
const resetRecordState = () => {
  isRecording.value = false;
  isCancel.value = false;
  recordDuration.value = 0;
  tempFilePath.value = '';
};

// 上传录音到服务器
const uploadVoice = (filePath) => {
  if (!filePath) return;

  uni.showLoading({ title: '发送中...' });
  
  // 调用上传接口
  uni.uploadFile({
    url: `${HTTP_REQUEST_URL}/mini/chat/file/voiceUpload`, // 替换为你的后端接口
    filePath,
    name: 'file',        // 后端接收文件的参数名
    formData: {
      duration: recordDuration.value // 携带录音时长
    },
    method: 'POST',
    header: {
      "Authorization": appStore.token
    },
    success: (res) => {
      console.log('上传结果:', res);
      const result = JSON.parse(res.data);
      if (result.code === 200) {
        // 上传成功，添加到消息列表
        sendMessage({ chatType:0,msgContent:result.data });
        // messages.value.push({
        //   id: Date.now(),
        //   isMine: true,
        //   avatar: '/static/avatar/user.png',
        //   duration: recordDuration.value,
        //   url: result.data.url, // 服务器返回的音频地址
        //   isPlaying: false
        // });
      } else {
        uni.showToast({ title: '发送失败', icon: 'none' });
      }
    },
    fail: (err) => {
      console.error('语音上传失败:', err);
      uni.showToast({ title: '发送失败', icon: 'none' });
    },
    complete: () => {
      uni.hideLoading();
    }
  });
};
</script>

<style scoped lang="scss">
.mine_ybt_title{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 1;
}
/* 录音区域 */
.record-btn{
  flex: 1;
  height: 70rpx;
  line-height: 70rpx;
  font-size: 30rpx;
  color: #333;

}
.record-area {
  padding: 30rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.record-btn {
  flex: 1;
  height: 70rpx;
  line-height: 70rpx;
  font-size: 30rpx;
  color: #333;
  background-color: #f2f2f2;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
}

.record-btn.recording {
  background-color: #ff4d4f;
  color: #fff;
}

.record-btn.cancel {
  background-color: #999;
}
/* 整体容器样式 */
.chat-container {
  display: flex;
  flex-direction: column;
  height: 100vh;
  // padding-bottom: 200rpx;
  /* background-color: #f5f5f5; */
}

/* 聊天消息区域样式 */
.chat-messages {
  flex: 1;
  overflow-y: auto;
  .scrollViewRef{
    // height: 100%;
     padding: 16rpx;
     overflow-y: auto;
  }
  // height: calc(100vh - 200rpx);
}



/* 输入区域样式 */
.input-area {
  // position: fixed;
  // left: 0;
  // bottom: 0;
  // width: 100%;
  display: flex;
  align-items: center;
  background-color: #fff;
  padding: 30rpx 40rpx;
  border-top: 1rpx solid #e0e0e0;
  position: relative;
}
.ai-tip{
  position: absolute;
  bottom: 5rpx;
  width: calc(100% - 80rpx);
  text-align: center;
  font-size: 20rpx;
  color: #999;
}

/* 图片图标样式 */
.image-btn{
  margin-right: 30rpx;
  width: 40rpx;
  height: 40rpx;
  &[disabled]{
    .image-icon{
      opacity: 0.4;
    }
  }
  .image-icon {
    width: 100%;
    height:100%;
  }
}

/* 输入框样式 */
.input-box {
  flex: 1;
  height: 70rpx;
  font-size: 30rpx;
  color: #333;
  background-color: transparent;
}

/* 麦克风图标样式 */
.isvoice-btn{
  width: 40rpx;
  height: 40rpx;
  margin: 0 40rpx;
  &[disabled]{
    .mic-icon{
      opacity: 0.4;
    }
  }
  .mic-icon {
    width: 100%;
    height:100%;
  }
}

/* 发送按钮样式 */
.send-btn {
  width: 60rpx;
  height: 60rpx;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  &[disabled]{
    .send-icon{
      opacity: 0.4;
    }
  }
}

/* 发送图标样式 */
.send-icon {
  width: 100%;
  height: 100%;
}

/* 录音提示 */
.record-toast {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 300rpx;
  height: 300rpx;
  border-radius: 20rpx;
  background-color: rgba(0, 0, 0, 0.7);
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 999;
}

.record-toast.cancel {
  background-color: rgba(255, 77, 79, 0.8);
}

.toast-icon {
  width: 200rpx;
  height: 200rpx;
  margin-bottom: 20rpx;
}
</style>