<template>
  <view class="ai-page" :style="{ paddingBottom: paddingBottom + 'px' }">
    <page-meta
      :page-style="'overflow:' + (show ? 'hidden' : 'visible')"
    ></page-meta>
    <top @clickLeft="openDrawer"></top>
    <scroll-view
      class="content"
      :scroll-y="true"
      show-scrollbar="false"
      scroll-with-animation
      ref="scrollView"
    >
      <front @onSuggestionTap="onSuggestionTap" />
      <chat :messages="messages" @playVoice="playVoice" />
      <view style="height: 12px" />
    </scroll-view>

    <view class="dock">
      <scroll-view
        class="quick-actions horizontal"
        scroll-x
        show-scrollbar="false"
      >
        <view class="qa-btn minor" @tap="onSwitchModel">切换模型</view>
        <view
          class="qa-btn"
          @tap="onQuickAsk(item.quickAskText)"
          v-for="item in quickAskList"
          :key="item.id"
        >
          {{ item.label }}
        </view>
      </scroll-view>
      <view class="input-bar">
        <input
          class="input"
          confirm-type="send"
          :value="inputText"
          @input="onInput"
          @confirm="onSend()"
          placeholder="你可以说…"
          placeholder-class="ph"
        />
        <view
          :class="['mic', { recording: isRecording }]"
          @touchstart.stop="onPressMic"
          @touchmove.stop="onMoveMic"
          @touchend.stop="onReleaseMic"
          >🎙️</view
        >
        <button class="send" type="primary" @tap="onSend">发送</button>
      </view>
    </view>

    <leftDrawer
      :historyGroups="historyGroups"
      ref="popup"
      @changeShow="changeShow"
      @onHistoryItemTap="onHistoryItemTap"
      @removeFromHistory="removeFromHistory"
      @clearAllHistory="clearAllHistory"
    />

    <!-- Voice recording overlay -->
    <view v-if="isRecording" class="record-mask">
      <view class="record-box" :class="{ cancel: willCancel }">
        <view class="record-icon">🎙️</view>
        <view class="record-text">{{
          willCancel ? "松开手指，取消发送" : "手指上滑，取消发送"
        }}</view>
      </view>
    </view>

    <view v-if="isRecording" class="mask-layer" @touchmove.stop.prevent> </view>
  </view>
</template>

<script>
const HISTORY_KEY = "chat_history_groups";
import { getAIResponse } from "@/api/index.js";
import top from "./top/index.vue";
import front from "./front/index.vue";
import chat from "./chat/index.vue";
import leftDrawer from "./leftDrawer/index.vue";
import { recognizeAudio } from "@/utils/uploadVoice.js";
export default {
  components: {
    top,
    front,
    chat,
    leftDrawer,
  },
  data() {
    return {
      inputText: "",
      messages: [],
      historyGroups: [],
      isRecording: false,
      isLoading: false,
      willCancel: false,
      recorder: null,
      recordStartY: 0,
      recordStartTs: 0,
      recordSimTimer: null,
      innerAudioContext: null,
      typewriterTimers: {},
      quickAskList: [
        {
          id: 1,
          label: "自我介绍",
          quickAskText: "你是谁?",
        },
        {
          id: 2,
          label: "快捷提问",
          quickAskText: "今日任务有哪些?",
        },
        {
          id: 3,
          label: "快捷提问",
          quickAskText: "展示一份报表示例",
        },
        {
          id: 4,
          label: "快捷提问",
          quickAskText: "生成日报模版",
        },
      ],
      show: false,
      paddingBottom: 0,
    };
  },
  mounted() {
    this.loadChatHistory();
    this.scrollToBottom();
    let self = this;
    uni.onKeyboardHeightChange((res) => {
      self.paddingBottom = res.height;
    });
  },
  beforeDestroy() {
    // 清理所有打字机定时器
    Object.values(this.typewriterTimers).forEach((timer) => {
      if (timer) clearInterval(timer);
    });
    this.typewriterTimers = {};
    // 清理录音定时器
    if (this.recordSimTimer) {
      clearTimeout(this.recordSimTimer);
    }
  },
  methods: {
    // top   打开历史记录
    openDrawer() {
      this.$refs.popup.open();
    },
    // front  猜你想问
    onSuggestionTap(text) {
      this.inputText = text;
      this.onSend();
    },
    //  leftDrawer  点击历史记录搜索
    onHistoryItemTap(text) {
      this.inputText = text;
      this.onSend();
      this.$refs.popup.close();
    },
    // leftDrawer 打开历史记录，聊天页面禁止滚动
    changeShow(e) {
      this.show = e;
    },
    // leftDrawer  删除历史记录
    removeFromHistory(text) {
      let groups = uni.getStorageSync(HISTORY_KEY)?.groups || [];
      groups.forEach((group) => {
        group.items = group.items.filter((item) => item !== text);
      });
      groups = groups.filter((g) => g.items.length > 0);
      this.historyGroups = groups;
      uni.setStorageSync(HISTORY_KEY, {
        groups,
        updatedAt: Date.now(),
      });
    },

    // leftDrawer 清除全部历史记录
    clearAllHistory() {
      uni.showModal({
        title: "清除全部",
        content: "将删除所有对话记录，此操作不可恢复",
        success: (res) => {
          if (res.confirm) {
            uni.removeStorageSync(HISTORY_KEY);
            this.historyGroups = [];
            uni.showToast({
              title: "已清除",
              icon: "success",
            });
          }
        },
      });
    },
    // ==================== 历史记录管理 ====================
    formatDate(date) {
      const y = date.getFullYear();
      const m = String(date.getMonth() + 1).padStart(2, "0");
      const d = String(date.getDate()).padStart(2, "0");
      return `${y}年${m}月${d}日`;
    },
    // 加载历史记录
    loadChatHistory() {
      try {
        const data = uni.getStorageSync(HISTORY_KEY);
        if (data && Array.isArray(data.groups)) {
          this.historyGroups = data.groups;
        } else {
          this.historyGroups = [];
        }
      } catch (e) {
        this.historyGroups = [];
      }
    },
    // 添加历史记录
    addToHistory(text) {
      let groups = uni.getStorageSync(HISTORY_KEY)?.groups || [];
      const today = this.formatDate(new Date());
      let todayGroup = groups.find((g) => g.date === today);

      if (!todayGroup) {
        todayGroup = {
          date: today,
          items: [],
        };
        groups.unshift(todayGroup);
      }

      if (!todayGroup.items.includes(text)) {
        todayGroup.items.unshift(text);
      }

      // 限制大小
      if (todayGroup.items.length > 50)
        todayGroup.items = todayGroup.items.slice(0, 50);
      if (groups.length > 30) groups = groups.slice(0, 30);

      this.historyGroups = groups;
      uni.setStorageSync(HISTORY_KEY, {
        groups,
        updatedAt: Date.now(),
      });
    },
	// 快速提问
    onQuickAsk(text) {
      this.inputText = text;
      this.onSend();
    },
	// 模型切换
    onSwitchModel() {
      uni.showToast({
        title: "已切换为通用模型",
        icon: "none",
      });
    },

    // onInput(e) {
    //   this.inputText = e.detail.value;
    // },

    // ===== Voice input (WeChat-like) =====
    ensureRecorder() {
      if (this.recorder) return;
      try {
        this.recorder = uni.getRecorderManager && uni.getRecorderManager();
      } catch (e) {
        this.recorder = null;
      }
      if (this.recorder) {
        this.recorder.onStart();
        this.recorder.onStop(async (res) => {
          const duration = Date.now() - this.recordStartTs;
          if (this.willCancel || duration < 700) {
            uni.showToast({
              title: duration < 700 ? "说话时间太短" : "已取消",
              icon: "none",
            });
            return;
          }
          uni.showLoading({
            title: "识别中...",
          });
          const text = await recognizeAudio(res.tempFilePath);
          uni.hideLoading();
          this.inputText = text;
          // TODO: 上传 res.tempFilePath 做识别；现用 mock
          // this.handleRecognizedText(this.mockSpeechToText(duration), res.tempFilePath, Math.ceil(
          // 	duration / 100) / 10)
          this.onSend();
        });
      }
    },
	// 按下录音
    onPressMic(e) {
      if (this.isLoading)
        return uni.showToast({
          title: "AI正在回复中",
          icon: "none",
        });
      this.ensureRecorder();
      this.isRecording = true;
      this.willCancel = false;
      this.recordStartTs = Date.now();
      this.recordStartY =
        e.changedTouches && e.changedTouches[0]
          ? e.changedTouches[0].clientY
          : 0;
      if (this.recorder) {
        try {
          this.recorder.start({
            format: "amr",
            sampleRate: 16000,
            numberOfChannels: 1,
            duration: 60000,
          });
        } catch (err) {}
      } else {
        if (this.recordSimTimer) clearTimeout(this.recordSimTimer);
        this.recordSimTimer = setTimeout(() => {}, 60000);
      }
    },
	// 录音时移动
    onMoveMic(e) {
      if (!this.isRecording) return;
      const y =
        e.changedTouches && e.changedTouches[0]
          ? e.changedTouches[0].clientY
          : 0;
      this.willCancel = this.recordStartY - y > 60;
    },
	// 松开录音
    onReleaseMic() {
      if (!this.isRecording) return;
      this.isRecording = false;
      this.show = false;
      if (this.recorder) {
        try {
          this.recorder.stop();
        } catch (err) {
          console.log("err", err);
        }
      }
    },

    // handleRecognizedText(text, tempFilePath, duration) {
    //   if (!text) return;
    //   this.inputText = text;
    //   this.onSend("voice", tempFilePath, duration); // 传 'voice'
    // },
    // mockSpeechToText(ms) {
    //   const sec = Math.ceil(ms / 100) / 10;
    //   const pool = [
    //     `语音输入 ${sec}s，模拟识别：帮我统计今天销售额`,
    //     `语音输入 ${sec}s，模拟识别：查询订单20388993483`,
    //     `语音输入 ${sec}s，模拟识别：生成日报`,
    //   ];
    //   return pool[Math.floor(Math.random() * pool.length)];
    // },
	// 发送消息
    async onSend(inputType = "text", inputContent = "", duration = undefined) {
      const text = (this.inputText || "").trim();
      if (!text || this.isLoading) return;
      const baseId = Date.now();
      // 1. 用户消息
      this.messages.push({
        id: baseId,
        role: "user",
        type: "text",
        content: text,
        inputType: typeof inputType === "string" ? inputType : "text",
        inputContent,
        duration,
      });

      // 2. loading 消息
      const loadingId = baseId + 0.5;
      this.messages.push({
        id: loadingId,
        role: "assistant",
        loading: true,
      });
      this.scrollToBottom();
      this.inputText = "";
      this.isLoading = true;
      this.addToHistory(text);
      try {
        // 3. 真正等待 AI 回复
        const reply = await getAIResponse({
          message: text,
        });
        // 4. 移除 loading
        const loadingIdx = this.messages.findIndex((m) => m.id === loadingId);
        if (loadingIdx > -1) this.messages.splice(loadingIdx, 1);

        // 5. 添加回复 + 打字机
        const replyId = baseId + 1;
        this.messages.push({
          id: replyId,
          role: "assistant",
          type: "text",
          content: reply,
          displayText: "",
        });
        this.typewriter(replyId, reply);
      } catch (e) {
        // 出错时也展示
        const loadingIdx = this.messages.findIndex((m) => m.id === loadingId);
        if (loadingIdx > -1) this.messages.splice(loadingIdx, 1);
        this.messages.push({
          id: baseId + 1,
          role: "assistant",
          content: `请求出错：${e.message || e}`,
        });
      } finally {
        console.log("finally");
        this.isLoading = false;
        this.$nextTick(() => this.scrollToBottom());
      }
    },
	// 打印机效果，并清除加载动画
    typewriter(messageId, fullText) {
      const msg = this.messages.find((m) => m.id === messageId);
      if (!msg) return;
      // 清理之前的定时器（如果存在）
      if (this.typewriterTimers[messageId]) {
        clearInterval(this.typewriterTimers[messageId]);
      }
      let index = 0;
      msg.displayText = fullText.substring(0, index + 1);
      index += 1;
      const speed = 50; // 每个字符间隔50ms
      const timer = setInterval(() => {
        if (index < fullText.length) {
          msg.displayText = fullText.substring(0, index + 1);
          index++;
          this.scrollToBottom();
        } else {
          clearInterval(timer);
          delete this.typewriterTimers[messageId];
          // 完成后使用完整文本
          msg.displayText = fullText;
        }
      }, speed);
      this.typewriterTimers[messageId] = timer;
    },
	// 滚动到底部
    scrollToBottom() {
      let self = this;
      this.$nextTick(() => {
        uni
          .createSelectorQuery()
          .select(".content")
          .boundingClientRect((rect) => {
            if (self.height !== rect.height) {
              self.height = rect.height;
              uni.pageScrollTo({
                scrollTop: rect.height,
                duration: 300,
                class: ".content",
              });
            }
          })
          .exec();
      });
    },
  },
};
</script>

<style scoped>
::v-deep .uni-nav-bar-text {
  font-size: 18px !important;
}

::v-deeo .uni-navbar--border {
  border-bottom: 1px solid #fff !important;
}

.ai-page {
  display: flex;
  flex-direction: column;
  background: #f7f8fc;
}

.content {
  flex: 1;
  padding: 16px 12px 74px 12px;
  background-color: #f7f8fc;
  width: 100%;
  box-sizing: border-box;
}

/* bottom dock */
.dock {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: #f7f8fc;
  box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.06);
  padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom);
}

.quick-actions {
  padding: 6px 10px 4px;
}

.quick-actions.horizontal {
  white-space: nowrap;
  width: 95%;
}

.qa-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 96px;
  text-align: center;
  background: #fff;
  border-radius: 10px;
  padding: 8px 10px;
  font-size: 12px;
  color: #3b3f45;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
  margin-right: 10px;
}

.qa-btn.minor {
  background: #eff1ff;
  color: #4e7bff;
}

.qa-btn:last-child {
  margin-right: 0;
}

.input-bar {
  display: flex;
  align-items: center;
  padding: 8px 10px 12px;
  gap: 8px;
  background: #f7f8fc;
}

.input {
  flex: 1;
  background: #fff;
  border-radius: 24px;
  padding: 10px 14px;
  font-size: 14px;
}

.ph {
  color: #9aa3b2;
}

.mic {
  width: 36px;
  height: 36px;
  border-radius: 18px;
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
}

.mic.recording {
  background: #fffbf0;
  box-shadow: 0 0 0 2px rgba(255, 193, 7, 0.25) inset;
}

.send {
  height: 36px;
  line-height: 36px;
  padding: 0 14px;
  border-radius: 18px;
  background: #4e7bff;
  color: #fff;
  font-size: 14px;
}

/* voice overlay */
.record-mask {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 9999;
}

.record-box {
  background: rgba(0, 0, 0, 0.75);
  color: #fff;
  padding: 16px 18px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 220rpx;
}

.record-text {
  font-size: 14px;
}

.mask-layer {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.1);
}

.history-popup {
  z-index: 99999;
}

::v-deep .drawer-scroll {
  padding-top: 44px;
}
</style>
