<template>
  <div v-if="state.isShowSearch" class="ai-float-window ai-float-fullscreen">
    <div class="ai-float-main">
      <div class="ai-float-left" v-if="isShowLeft">
        <component :is="currentComponent" v-bind="currentProps" v-if="currentComponent"/>
      </div>
      <div class="ai-float-right" v-loading="aiLoading">
        <div class="ai-float-header" @mousedown="onDragStart">
          <span>AI智能填报助手</span>
          <el-icon class="ai-float-close" @click="close">
            <Close/>
          </el-icon>
        </div>
        <div class="ai-float-form-list ai-float-scroll">
          <div class="ai-float-welcome">👋 欢迎使用AI智能填报助手</div>
          <div class="form-list-title">请选择需要填报的表单：</div>
          <!-- 加载状态 -->
          <div v-if="formsLoading" class="loading-container">
            <el-icon class="is-loading">
              <Loading/>
            </el-icon>
            <span>加载表单中...</span>
          </div>
          <!-- 表单列表 -->
          <div v-else class="form-list">
            <el-tag
              v-for="aiFormSetting in aiFormSettingList"
              :key="aiFormSetting.formSettingId"
              :type="aiFormSetting.formSettingId === selectedFormSettingId ? 'success' : 'info'"
              class="form-tag"
              @click="selectForm(aiFormSetting)"
              effect="dark"
            >
              {{ aiFormSetting.formName }}
            </el-tag>
            <el-button v-if="aiFormSettingList.length > 5" type="text" class="more-btn" @click="showMore = !showMore">
              更多
            </el-button>
          </div>
          <el-dialog v-model="showMore" title="选择其他表单" width="400px" @close="moreFilterText = ''">
            <el-input
              v-model="moreFilterText"
              placeholder="输入表单名称过滤"
              clearable
              style="margin-bottom: 12px;"
            />
            <el-scrollbar style="max-height:300px;">
              <el-tag
                v-for="form in filteredForms"
                :key="form.formSettingId"
                :type="form.formSettingId === selectedFormSettingId ? 'success' : 'info'"
                class="form-tag"
                style="margin-bottom: 8px;"
                @click="selectForm(form); showMore = false"
                effect="dark"
              >
                {{ form.formName }}
              </el-tag>
            </el-scrollbar>
          </el-dialog>
        </div>
        <!-- 聊天区始终渲染，内容为空时不显示消息 -->
        <div class="ai-float-chat-list" ref="chatListRef">
          <div v-for="(msg, idx) in chatList" :key="idx"
               :class="['ai-float-chat-item', msg.from === 'ai' ? 'ai-chat-ai' : 'ai-chat-user']">
            <template v-if="msg.from === 'ai'">
              <div class="ai-avatar">🤖</div>
              <div class="ai-float-chat-bubble ai-float-chat-bubble-ai">
                <div v-if="msg.type === 'select' && msg.selectLists">
                  <div class="ai-select-title" style="font-weight:bold; margin-bottom:8px;">{{ msg.text }}</div>
                  <div class="ai-select-lists">
                    <div v-for="(list, lidx) in msg.selectLists" :key="lidx" class="ai-select-list-block">
                      <div class="ai-select-list-title">{{ list.title }}</div>
                      <div class="ai-select-options">
                        <el-button v-for="opt in list.options.slice(0,4)" :key="opt" size="small"
                                   @click="() => handleSelectOption(opt)"
                                   :type="selectedOption === opt ? 'primary' : 'default'">{{ opt }}
                        </el-button>
                        <el-button v-if="list.options.length > 4" size="small" type="primary" link
                                   @click="() => openSelectDialog(list)">更多
                        </el-button>
                      </div>
                    </div>
                  </div>
                </div>
                <div v-else v-html="formatMsg(msg.text)"></div>
              </div>
            </template>
            <template v-else>
              <div class="ai-float-chat-bubble-user-wrap">
                <div class="ai-float-chat-bubble" v-html="formatMsg(msg.text)"></div>
                <div class="ai-avatar ai-avatar-user">👤</div>
              </div>
            </template>
          </div>
        </div>
        <el-dialog v-model="selectDialog" title="更多选项" width="400px" @close="selectDialogFilterText = ''">
          <div v-if="selectDialogList">
            <div class="ai-select-title">{{ selectDialogList.title }}</div>
            <el-input
              v-model="selectDialogFilterText"
              placeholder="输入关键字过滤"
              clearable
              style="margin-bottom: 12px;"
            />
            <div class="ai-select-options">
              <el-button v-for="opt in filteredSelectDialogOptions" :key="opt" size="small"
                         @click="() => handleSelectOption(opt)" :type="selectedOption === opt ? 'primary' : 'default'">
                {{ opt }}
              </el-button>
            </div>
          </div>
        </el-dialog>
        <div class="ai-float-input-area">
          <div v-if="selectedFormSettingId" class="ai-float-form-info">
            <div class="form-info-title">
              当前表单：{{ aiFormSettingList.find(f => f.formSettingId === selectedFormSettingId)?.formName }}
            </div>
            <div class="form-info-tip">请根据下方示例填写内容，AI将自动为您智能填报。</div>
            <div class="form-info-example">示例：如"申请10个物料A用于生产线1，计划交付日期为2024-07-01"</div>
          </div>
          <div class="ai-float-input-row">
            <el-input
              v-model="inputValue"
              type="textarea"
              :rows="2"
              :autosize="{ minRows: 2, maxRows: 6 }"
              :maxlength="300"
              :disabled="!selectedFormSettingId || aiThinking"
              placeholder="请输入内容（最多300字符）"
              @keydown="onInputKeydown"
              class="ai-float-input"
              show-word-limit
              clearable
            />
            <el-button
              class="ai-float-send-btn"
              :disabled="!canSend || aiThinking"
              icon="el-icon-s-promotion"
              @click="() => handleSend()"
              circle
              type="primary"
            />
            <el-button
              @click="toggleRecording"
              :class="{ 'recording': isRecording }"
              v-loading="audioAsrLoading"
            >
              {{ isRecording ? '停止录音' : '开始录音' }}
            </el-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {ref, reactive, computed, onMounted, onBeforeUnmount, nextTick, shallowRef, watch, getCurrentInstance} from 'vue'
import {ElMessage} from 'element-plus'
import {Close, Loading} from '@element-plus/icons-vue'
import type {ComponentInternalInstance} from 'vue'
import {getAiFormSettingList, getAiFormSettingDetailList} from '@/api/ai/base/aiFormSetting';
import {AiFormSettingVO, AiFormSettingDetailVO} from '@/api/ai/base/aiFormSetting/types';
import {aiFillForm, recognizeSpeechByUrl, uploadFile} from '@/api/ai/skill/aiAssistant';
import router from "@/router"

const {proxy} = getCurrentInstance() as ComponentInternalInstance

const aiFormSettingList = ref<AiFormSettingVO[]>([])
const aiFormSettingDetailListMap = ref<Record<number, AiFormSettingDetailVO[]>>({});
const selectedFormSettingId = ref<number | null>(null)
const formsLoading = ref(false)
const isShowLeft = ref(false);
const aiLoading = ref(false);

// 用reactive对象直接定义state
const state = reactive({
  isShowSearch: false,
  menuQuery: '',
  menuList: []
});

// 搜索弹窗打开
const openSearch = () => {
  state.menuQuery = '';
  state.isShowSearch = true;
  nextTick(() => {
    setTimeout(() => {
      // layoutMenuAutocompleteRef.value.focus();
    });
  });
};

// 动态生成的表单页面映射
const formPageMap = ref<Record<number, { loader: () => Promise<any>, props: any }>>({})

// 加载表单数据并初始化formPageMap
const loadForms = async () => {
  try {
    formsLoading.value = true
    const res = await getAiFormSettingList({})
    if (res.code === 200) {
      aiFormSettingList.value = res.data || []
      // 动态生成formPageMap
      initFormPageMap()
    }
  } catch (error) {
    console.error('加载表单数据失败:', error)
    ElMessage.error('加载表单数据失败')
  } finally {
    formsLoading.value = false
  }
}

// 动态生成formPageMap
const initFormPageMap = () => {
  const newFormPageMap: Record<number, { loader: () => Promise<any>, props: any }> = {}

  aiFormSettingList.value.forEach(form => {
    // // 根据表单的formPath字段动态生成组件路径
    // let componentPath = form.formPath
    // if(!form.dialogVisibleVariable ||  form.dialogVisibleVariable===''){
    //   componentPath = '../../../views/'+componentPath;
    // }else{
    //   componentPath = "/"+componentPath;
    // }
    // 创建动态加载器
    const loader = () => {
      try {
        // const dd = new URL(`@/views/system/user/index.vue`, import.meta.url).href;
        // return import(`${componentPathUrl}`);
        if (!form.dialogVisibleVariable || form.dialogVisibleVariable === '') {
          const componentPath = '../../../views/' + form.formPath;
          return import(/* @vite-ignore */ componentPath)
        }
      } catch (error) {
        // console.error(`加载组件失败: ${componentPath}`, error)
        // return import('@/views/ai/skill/aiForm/index.vue')
      }
    }

    // 根据表单类型设置不同的props
    const props = getFormProps(form)

    newFormPageMap[form.formSettingId] = {loader, props}
  })

  formPageMap.value = newFormPageMap
}

// 根据表单信息生成props
const getFormProps = (form: AiFormSettingVO) => {
  const baseProps = {
    formSettingId: form.formSettingId,
    formName: form.formName,
    formType: form.formType,
    dialogVisibleVariable: form.dialogVisibleVariable,
    formPath: form.formPath,
    userInput: ''
  }

  // 根据表单类型添加特定props
  switch (form.formType) {
    case 'system':
      return {...baseProps, pageNum: 1, pageSize: 10}
    case 'ai':
      return {...baseProps, aiType: 'form', mode: 'edit'}
    default:
      return baseProps
  }
}

const selectForm = async (aiFormSetting: AiFormSettingVO) => {
  selectedFormSettingId.value = aiFormSetting.formSettingId
  aiLoading.value = true
  try {
    if (!aiFormSettingDetailListMap.value[aiFormSetting.formSettingId]) {
      const res = await getAiFormSettingDetailList(
        {formSettingId: aiFormSetting.formSettingId, settingFlag: '1'})
      if (res.code === 200) {
        aiFormSettingDetailListMap.value[aiFormSetting.formSettingId] = res.data || []
      }
    }
  } finally {
    aiLoading.value = false
  }
  console.log(aiFormSettingDetailListMap.value[aiFormSetting.formSettingId])
}

// function selectForm(aiFormSetting: AiFormSettingVO) {
//   selectedFormSettingId.value = aiFormSetting.formSettingId
//   if(!aiFormSettingDetailListMap[aiFormSetting.formSettingId]){
//     const res = await getAiFormSettingDetailList({formSettingId: aiFormSetting.formSettingId})
//     if (res.code === 200) {
//       aiFormSettingDetailListMap.value[aiFormSetting.formSettingId] = res.data || []
//     }
//   }
// }


const currentComponent = shallowRef(null)
const currentProps = ref({})
watch(selectedFormSettingId, async (formSettingId) => {
  if (formSettingId && formPageMap.value[formSettingId]) {
    try {
      if (formPageMap.value[formSettingId].props && formPageMap.value[formSettingId].props.dialogVisibleVariable && formPageMap.value[formSettingId].props.dialogVisibleVariable !== '') {
        isShowLeft.value = false
        router.push("/" + formPageMap.value[formSettingId].props.formPath)
        // proxy.$store.commit('aiFormSettingId', formSettingId)
        // proxy.$store.commit('aiFormSetting', formPageMap.value[formSettingId])
      } else {
        isShowLeft.value = true
        const mod = await formPageMap.value[formSettingId].loader()
        console.log(formPageMap.value[formSettingId].props)
        currentComponent.value = mod.default
        currentProps.value = {...formPageMap.value[formSettingId].props, userInput: ''}
      }


    } catch (error) {
      console.error('加载表单组件失败:', error)
      ElMessage.error('加载表单组件失败')
      currentComponent.value = null
      currentProps.value = {}
    }
  } else {
    currentComponent.value = null
    currentProps.value = {}
  }
})

// 暴露变量
defineExpose({
  openSearch
});


watch(state, (newVal) => {
  if (newVal.isShowSearch) {
    loadForms()
  }
});


const handleSend = async (selectedText?: string) => {
  if ((!canSend.value || aiThinking.value) && !selectedText) return
  const userMsg = selectedText || inputValue.value
  chatList.value.push({text: userMsg, from: 'user', type: 'text'})
  scrollToBottom()
  aiThinking.value = true
  inputValue.value = 'AI思考中....'
  aiLoading.value = true
  console.log(aiFormSettingDetailListMap.value[selectedFormSettingId.value]);
  try {
    let params = {
      naturalLanguageQuery: userMsg,
      formSettingId: selectedFormSettingId.value,
      formSettingDetailList: aiFormSettingDetailListMap.value[selectedFormSettingId.value],
      modelId: 1,
      platformId: 1
    }

    // currentProps.value = {completeAmount:10,productionTime:16.6};
    // return;

    const response = await aiFillForm(params)
    currentProps.value = response;
    inputValue.value = ''
    aiThinking.value = false
    // 固定AI回复+多个选择列表
    chatList.value.push({
      text: '操作成功，请选择相关信息：',
      from: 'ai',
      type: 'select',
      selectLists: [
        {title: '物料信息', options: ['物料A', '物料B', '物料C', '物料D', '物料E', '物料F']},
        {title: 'BOM信息', options: ['BOM-001', 'BOM-002', 'BOM-003', 'BOM-004', 'BOM-005']}
      ]
    })
    scrollToBottom()

    console.log(1)
    console.log(response)
    console.log(2)

  } catch (error) {
    proxy?.$modal.msgError(error);
    console.log("Error:" + error)

  } finally {
    aiLoading.value = false
  }
}

// 录音相关对象
const isRecording = ref(false);
let mediaRecorder = null
let microphoneStream = null
let audioChunks = []
let audioContext = null
const targetSampleRate = 16000 // 目标采样率，可根据后端要求调整

// 状态变量
const audioAsrLoading = ref(false);
const isUploading = ref(false)
const uploadProgress = ref(0)
const recognitionResult = ref('')
const recordings = ref([])

const toggleRecording = () => {
  if (isRecording.value) {
    stopRecording();
  } else {
    startRecording();
  }
}

// 开始录音
async function startRecording() {
  alert('您的浏览器不支持录音功能1')
  proxy.$modal.msgError('您的浏览器不支持录音功能')
  try {
    // 检查浏览器支持
    if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
      proxy.$modal.msgError('您的浏览器不支持录音功能')
      return
    }

    // 获取用户麦克风权限
    microphoneStream = await navigator.mediaDevices.getUserMedia({
      audio: {
        echoCancellation: true,
        noiseSuppression: true,
        autoGainControl: true
      }
    })

    // 初始化Web Audio API用于后续处理
    if (!audioContext) {
      audioContext = new (window.AudioContext)()
    }

    // 设置MediaRecorder
    const options = {
      mimeType: 'audio/webm;codecs=opus' // 优先使用opus编码
    }

    // 降级处理，确保兼容性
    if (!MediaRecorder.isTypeSupported(options.mimeType)) {
      options.mimeType = 'audio/webm'
      if (!MediaRecorder.isTypeSupported(options.mimeType)) {
        options.mimeType = 'audio/ogg;codecs=opus'
        if (!MediaRecorder.isTypeSupported(options.mimeType)) {
          proxy.$modal.msgError('您的浏览器不支持高质量录音格式')
          return
        }
      }
    }

    mediaRecorder = new MediaRecorder(microphoneStream, options)
    audioChunks = []

    // 收集音频数据
    mediaRecorder.ondataavailable = (event) => {
      if (event.data.size > 0) {
        audioChunks.push(event.data)
      }
    }

    // 录音开始
    mediaRecorder.start()
    isRecording.value = true
    // addLog('录音已开始')

  } catch (error) {
    console.error('开始录音失败:', error)
    // addLog(`开始录音失败: ${error.message}`)
    stopRecording()
  }
}

// 停止录音
function stopRecording() {

  try {
    if (!isRecording.value) return
    // 更新录音状态
    isRecording.value = false
    // 停止MediaRecorder
    if (mediaRecorder && mediaRecorder.state !== 'inactive') {
      mediaRecorder.stop()
      // 录音停止后的处理
      mediaRecorder.onstop = async () => {
        audioAsrLoading.value = true;
        try {
          // 关闭麦克风流
          if (microphoneStream) {
            microphoneStream.getTracks().forEach(track => track.stop())
            microphoneStream = null
          }

          // addLog('录音已停止，正在处理音频...')

          // 将录音数据转换为WAV格式
          const wavBlob = await convertToWav(audioChunks)

          // 保存录音到历史记录
          const recordingName = `recording_${new Date().toISOString().replace(/[:.]/g, '-')}.wav`
          const recordingUrl = URL.createObjectURL(wavBlob)
          recordings.value.unshift({
            name: recordingName,
            url: recordingUrl,
            file: wavBlob
          })

          // 限制历史记录数量
          if (recordings.value.length > 5) {
            const oldestRecording = recordings.value.pop()
            URL.revokeObjectURL(oldestRecording.url)
          }

          // addLog(`音频处理完成，文件大小: ${(wavBlob.size / 1024).toFixed(2)}KB`)

          // 自动上传录音文件
          await uploadAudioFile(wavBlob, recordingName)

        } catch (error) {
          console.error('处理录音文件失败:', error)
          proxy.$modal.msgError('处理录音文件失败，请重试', error)
          // addLog(`处理录音文件失败: ${error.message}`)
        }finally{

        }
      }
    }

  } catch (error) {
    console.error('停止录音失败:', error)
    // addLog(`停止录音失败: ${error.message}`)
  } finally {

  }
}

// 将音频数据转换为WAV格式
async function convertToWav(audioChunks) {
  // 将音频块合并为单个Blob
  const audioBlob = new Blob(audioChunks)

  // 读取音频数据并转换为WAV
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader()
    fileReader.onload = async (e) => {
      try {
        // 获取ArrayBuffer
        const arrayBuffer = e.target.result

        // 使用Web Audio API解码音频数据
        const audioBuffer = await audioContext.decodeAudioData(arrayBuffer)

        // 转换为目标采样率的WAV格式
        const wavBuffer = await resampleAndConvertToWav(audioBuffer, targetSampleRate)

        resolve(new Blob([wavBuffer], {type: 'audio/wav'}))
      } catch (error) {
        reject(error)
      }
    }
    fileReader.onerror = reject
    fileReader.readAsArrayBuffer(audioBlob)
  })
}

// 重采样并转换为WAV格式
async function resampleAndConvertToWav(audioBuffer, targetRate) {
  // 获取原始音频数据
  const channels = audioBuffer.numberOfChannels
  const sampleRate = audioBuffer.sampleRate
  const length = audioBuffer.length

  // 计算重采样后的长度
  const newLength = Math.floor(length * targetRate / sampleRate)

  // 创建目标采样率的AudioContext
  const offlineContext = new OfflineAudioContext(channels, newLength, targetRate)

  // 创建缓冲区源节点
  const source = offlineContext.createBufferSource()
  source.buffer = audioBuffer

  // 连接到输出
  source.connect(offlineContext.destination)

  // 开始播放
  source.start()

  // 渲染重采样后的音频
  const renderedBuffer = await offlineContext.startRendering()

  // 将AudioBuffer转换为WAV格式
  return encodeWAV(renderedBuffer)
}

// 将AudioBuffer编码为WAV格式
function encodeWAV(audioBuffer) {
  const numberOfChannels = audioBuffer.numberOfChannels
  const sampleRate = audioBuffer.sampleRate
  const bitDepth = 16

  // 获取所有声道的数据
  const channels = []
  for (let i = 0; i < numberOfChannels; i++) {
    channels.push(audioBuffer.getChannelData(i))
  }

  // 计算总样本数
  const sampleCount = channels[0].length
  const byteRate = sampleRate * numberOfChannels * bitDepth / 8

  // 创建WAV文件头部
  const wavHeader = new ArrayBuffer(44)
  const view = new DataView(wavHeader)

  // RIFF标识符
  writeString(view, 0, 'RIFF')
  // 文件大小
  view.setUint32(4, 36 + sampleCount * numberOfChannels * 2, true)
  // WAVE标识符
  writeString(view, 8, 'WAVE')
  // fmt子块标识符
  writeString(view, 12, 'fmt ')
  // fmt子块大小
  view.setUint32(16, 16, true)
  // 音频格式（PCM）
  view.setUint16(20, 1, true)
  // 声道数
  view.setUint16(22, numberOfChannels, true)
  // 采样率
  view.setUint32(24, sampleRate, true)
  // 字节率
  view.setUint32(28, byteRate, true)
  // 块对齐
  view.setUint16(32, numberOfChannels * 2, true)
  // 位深度
  view.setUint16(34, bitDepth, true)
  // data子块标识符
  writeString(view, 36, 'data')
  // data子块大小
  view.setUint32(40, sampleCount * numberOfChannels * 2, true)

  // 创建PCM数据
  const pcmBytes = new ArrayBuffer(wavHeader.byteLength + sampleCount * numberOfChannels * 2)
  const pcmView = new DataView(pcmBytes)

  // 复制WAV头部
  for (let i = 0; i < wavHeader.byteLength; i++) {
    pcmView.setUint8(i, new Uint8Array(wavHeader)[i])
  }

  // 写入PCM数据
  let offset = 44
  for (let i = 0; i < sampleCount; i++) {
    for (let channel = 0; channel < numberOfChannels; channel++) {
      const sample = Math.max(-1, Math.min(1, channels[channel][i]))
      // 将Float32转换为Int16
      pcmView.setInt16(offset, sample < 0 ? sample * 0x8000 : sample * 0x7FFF, true)
      offset += 2
    }
  }

  return pcmBytes
}

// 写入字符串到DataView
function writeString(view, offset, string) {
  for (let i = 0; i < string.length; i++) {
    view.setUint8(offset + i, string.charCodeAt(i))
  }
}

// 上传音频文件
async function uploadAudioFile(blob, fileName) {
  try {
    isUploading.value = true
    uploadProgress.value = 0
    recognitionResult.value = ''

    // addLog(`开始上传音频文件: ${fileName}`)

    // 创建FormData对象
    const formData = new FormData()
    formData.append('file', blob, fileName)

    const response = await uploadFile(formData);
    console.log(response)

    // 处理响应
    if (response.code === 200) {
      // addLog('音频上传成功，正在识别')

      // alert(response.data.url)
      const response1 = await recognizeSpeechByUrl(response.data.url);
      if (response1.code === 200) {
        console.log("--" + response1);
        inputValue.value += response1.data.text
        // recognitionResult.value = response1.data.text || '识别成功，但未返回文本结果'
        // alert(recognitionResult.value)
        // addLog('识别成功，结果为: ' + recognitionResult.value)
      }
    } else {
      // addLog(`上传失败，状态码: ${response.status}`)
    }

  } catch (error) {
    console.error('上传音频文件失败:', error)
    proxy.$message.error('上传音频文件失败', error)
    // addLog(`上传音频文件失败: ${error.message || '未知错误'}`)
  } finally {
    isUploading.value = false
    uploadProgress.value = 0
  }
}


function handleSend1(selectedText?: string) {
  if ((!canSend.value || aiThinking.value) && !selectedText) return
  const userMsg = selectedText || inputValue.value
  chatList.value.push({text: userMsg, from: 'user', type: 'text'})
  // 动态传递userInput参数给左侧组件
  if (currentComponent.value) {
    currentProps.value = {...currentProps.value, userInput: userMsg}
  }
  scrollToBottom()
  aiThinking.value = true
  inputValue.value = 'AI思考中....'
  setTimeout(() => {
    inputValue.value = ''
    aiThinking.value = false
    // 固定AI回复+多个选择列表
    chatList.value.push({
      text: '操作成功，请选择相关信息：',
      from: 'ai',
      type: 'select',
      selectLists: [
        {title: '物料信息', options: ['物料A', '物料B', '物料C', '物料D', '物料E', '物料F']},
        {title: 'BOM信息', options: ['BOM-001', 'BOM-002', 'BOM-003', 'BOM-004', 'BOM-005']}
      ]
    })
    scrollToBottom()
  }, 2000)
}


const showMore = ref(false)
const inputValue = ref('')
const canSend = computed(() => selectedFormSettingId.value && inputValue.value.trim().length > 0)

// 新增：更多弹窗过滤输入
const moreFilterText = ref('')
const filteredForms = computed(() =>
  aiFormSettingList.value.filter(form => form.formName.includes(moreFilterText.value))
)

type ChatSelectList = { title: string, options: string[] }
type ChatMsg = { text: string, from: 'user' | 'ai', type?: 'text' | 'select', selectLists?: ChatSelectList[] }
const chatList = ref<ChatMsg[]>([])
const selectDialog = ref(false)
const selectDialogList = ref<ChatSelectList | null>(null)
const aiThinking = ref(false)
const chatListRef = ref<HTMLElement | null>(null)
const selectedOption = ref('')
const iframeRef = ref<HTMLIFrameElement | null>(null)

// 新增：AI更多弹窗过滤输入
const selectDialogFilterText = ref('')
const filteredSelectDialogOptions = computed(() =>
  selectDialogList.value
    ? selectDialogList.value.options.filter(opt => opt.includes(selectDialogFilterText.value))
    : []
)

// 悬浮窗拖拽
const floatStyle = reactive({
  left: '',
  top: '0px',
  width: '440px',
  height: '100vh',
  zIndex: 9999,
  position: 'fixed' as const,
})

// 默认显示在最右侧
onMounted(() => {
  floatStyle.left = (window.innerWidth - 440) + 'px';
  floatStyle.top = '0px';
  // 加载表单数据
  // loadForms()

})

let drag = false
let offsetX = 0
let offsetY = 0

function onDragStart(e: MouseEvent) {
  drag = true
  offsetX = e.clientX - parseInt(floatStyle.left)
  offsetY = e.clientY - parseInt(floatStyle.top)
  document.addEventListener('mousemove', onDragging)
  document.addEventListener('mouseup', onDragEnd)
}

function onDragging(e: MouseEvent) {
  if (!drag) return
  let newLeft = e.clientX - offsetX
  let newTop = e.clientY - offsetY
  // 限制在屏幕内
  newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - 440))
  newTop = Math.max(0, Math.min(newTop, window.innerHeight - 100))
  floatStyle.left = newLeft + 'px'
  floatStyle.top = newTop + 'px'
}

function onDragEnd() {
  drag = false
  document.removeEventListener('mousemove', onDragging)
  document.removeEventListener('mouseup', onDragEnd)
}

onBeforeUnmount(() => {
  document.removeEventListener('mousemove', onDragging)
  document.removeEventListener('mouseup', onDragEnd)
})

// 组件卸载时清理资源
onUnmounted(() => {
  // 停止MediaRecorder
  if (mediaRecorder && mediaRecorder.state !== 'inactive') {
    mediaRecorder.stop()
  }

  // 关闭音频上下文
  if (audioContext) {
    audioContext.close()
    audioContext = null
  }

  // 释放URL对象
  recordings.value.forEach(recording => {
    URL.revokeObjectURL(recording.url)
  })


})


function scrollToBottom() {
  nextTick(() => {
    if (chatListRef.value) {
      chatListRef.value.scrollTop = chatListRef.value.scrollHeight
    }
  })
}


// 保证所有方法直接在<script setup>中定义
function handleSelectOption(opt: string) {
  selectedOption.value = opt
}

function openSelectDialog(list: ChatSelectList) {
  selectDialogList.value = list
  selectDialog.value = true
}

function formatMsg(text: string) {
  // 转换换行符为<br>，并做简单转义防XSS
  return text
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/\n/g, '<br>')
}

function onInputKeydown(e: KeyboardEvent) {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault();
    handleSend();
  }
  // shift+enter 默认换行，无需处理
}

function close() {
  state.isShowSearch = false
}

// 搜索弹窗关闭
const closeSearch = () => {
  state.isShowSearch = false;
};


</script>

<style scoped lang="less">
.el-message {
  z-index:8006 !important;
}

.ai-float-fullscreen {
  position: fixed;
  left: 0;
  top: 0;
  width: 100vw;
  height: 100vh;
  z-index: 7005;
  background: #fff;
  border-radius: 0;
  box-shadow: none;
}

.ai-float-window {
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.18);
  background: #fff;
  border-radius: 12px;
  padding: 0 0 16px 0;
  min-height: 220px;
  user-select: none;
  display: flex;
  flex-direction: column;
  height: 100vh;
  width: 60vw;
  right: 0;
  left: auto;
  top: 0;
  position: fixed;
  z-index: 7005;
}

.ai-float-main {
  display: flex;
  height: 100vh;
}

.ai-float-left {
  flex: 7 7 0;
  min-width: 400px;
  background: #f7f8fa;
  border-right: 1px solid #e0e7ef;
  overflow: auto;
  height: 100%;
}

.ai-float-right {
  flex: 3 3 0;
  min-width: 260px;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.ai-float-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 18px;
  font-weight: bold;
  padding: 16px 24px 8px 24px;
  cursor: move;
  border-bottom: 1px solid #f0f0f0;
}

.ai-float-welcome {
  font-size: 16px;
  color: #409eff;
  margin-bottom: 10px;
  font-weight: 500;
}

.ai-float-close {
  font-size: 20px;
  cursor: pointer;
  color: #888;
  transition: color 0.2s;
}

.ai-float-close:hover {
  color: #f56c6c;
}

.ai-float-form-list {
  padding: 16px 24px 0 24px;
  flex-shrink: 0;
  max-height: 220px;
  overflow-y: auto;
}

.form-list-title {
  font-size: 15px;
  margin-bottom: 8px;
  color: #333;
}

.form-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}

.form-tag {
  cursor: pointer;
  margin-bottom: 4px;
}

.more-btn {
  margin-left: 8px;
  font-size: 13px;
  padding: 0 4px;
}

.loading-container {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  color: #666;
  gap: 8px;
}

.ai-float-input-area {
  padding: 6px 24px 0 24px;
  flex-shrink: 0;
  height: 140px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
}

.ai-float-form-info {
  margin-bottom: 8px;
  background: #f6f8fa;
  border-radius: 1px;
  padding: 10px 14px;
}

.form-info-title {
  font-weight: bold;
  color: #333;
  margin-bottom: 2px;
}

.form-info-tip {
  color: #666;
  font-size: 13px;
  margin-bottom: 2px;
}

.form-info-example {
  color: #999;
  font-size: 13px;
}

.ai-float-input-row {
  display: flex;
  align-items: flex-end;
  gap: 8px;
}

.ai-float-input {
  flex: 1 1 auto;
}

.ai-float-send-btn {
  margin-bottom: 4px;
}

.ai-float-chat-list {
  flex: 1 1 auto;
  margin: 0 24px;
  margin-top: 12px;
  margin-bottom: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-y: auto;
  min-height: 0;
  max-height: calc(100vh - 170px - 140px - 32px);
}

.ai-float-chat-item {
  display: flex;
  justify-content: flex-end;
  align-items: flex-end;
}

.ai-chat-ai {
  justify-content: flex-start;
}

.ai-avatar {
  width: 32px;
  height: 32px;
  background: linear-gradient(135deg, #e0e7ef 0%, #f6f8fa 100%);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  margin-right: 8px;
  box-shadow: 0 2px 8px rgba(64, 158, 255, 0.08);
}

.ai-float-chat-bubble {
  background: linear-gradient(135deg, #409eff 0%, #6ec1ff 100%);
  color: #fff;
  border-radius: 20px 20px 4px 24px;
  padding: 12px 22px;
  max-width: 80%;
  font-size: 14px;
  word-break: break-all;
  box-shadow: 0 4px 16px rgba(64, 158, 255, 0.13);
  line-height: 1.85;
  min-height: 36px;
  display: inline-block;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.ai-float-chat-bubble-ai {
  background: linear-gradient(135deg, #f4f4f4 0%, #e9f0fb 100%);
  color: #333;
  border-radius: 16px 16px 16px 6px;
  box-shadow: 0 2px 12px rgba(64, 158, 255, 0.10);
  border: 1px solid #e0e7ef;
}

.ai-select-lists {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: stretch;
}

.ai-select-list-block {
  width: 100%;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 0;
  margin: 0;
}

.ai-select-list-title {
  font-weight: 500;
  color: #333;
  text-align: left;
  width: 100%;
  margin: 0;
  padding: 0;
}

.ai-select-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  text-align: left;
  margin: 0;
  padding: 0;
}

.ai-select-options .el-button {
  width: 100%;
  text-align: left;
  margin: 0;
  padding-left: 0 !important;
  justify-content: flex-start;
}

.el-dialog__body .ai-select-title {
  margin-bottom: 8px;
}

.el-dialog__body .ai-select-options {
  width: 100%;
  justify-content: flex-start;
  gap: 8px;
}

.ai-float-chat-bubble-user-wrap {
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  gap: 8px;
}

.ai-avatar-user {
  background: linear-gradient(135deg, #e0e7ef 0%, #d0eaff 100%);
  color: #409eff;
}
</style>

