<template>
  <div class="ai-chat">
    <!-- 头部 -->
    <div class="ai-chat-header">
      <div class="ai-chat-header-info">
        <div class="logo">
          <img :src="chat.agentInfo?.imgRelUrl || '/images/def_agent.svg'" alt="" />
        </div>
        <div class="info flex-direction-column justify-center">
          <div class="info-title">{{ chat.agentInfo?.name || '' }}</div>
          <div class="info-sub-title">{{ chat.agentInfo?.applicationDesc || '' }}</div>
          <div class="info-user"><lz-svg-icon icon-class="user" :style="{ 'fontSize': '14px', marginRight: '2px' }" />
            {{ chat.agentInfo?.echoMap?.createdBy || '' }}</div>
        </div>
      </div>
    </div>
    <!-- 内容-->
    <el-scrollbar ref="scrollDiv" @scroll="handleScrollTop">
      <div ref="dialogScrollbar" class="ai-chat-box">
        <!--开场白，引导问题-->
        <div class="ai-chat-header-tips" v-if="chat.agentInfo?.tags?.length || chat.agentInfo?.opening">
          <div class="title pointer">{{ chat.agentInfo?.opening }}</div>
          <div class="tag pointer" v-for="item in chat.agentInfo?.questions" :key="item.id"
            @click="questionText = item.name">
            {{ item.name }}
          </div>
        </div>
        <!-- 问、答 -->
        <div class="ai-chat-content">
          <ul>
            <li v-for="(item, index) in chat.questionList" :key="item.id" :data-id="item.id">
              <!--问-->
              <div class="question">
                <div class="content-wrapper" style="margin-right: 8px">
                  <div class="content">{{ item.question }}</div>
                </div>
                <div class="avatar">
                  <img src="@/assets/user-icon.svg" alt="" />
                </div>
              </div>
              <!--答-->
              <div class="answer">
                <div class="avatar"><img :src="chat.agentInfo?.imgRelUrl || '/images/def_agent.svg'" alt="" /></div>
                <div class="content-wrapper" style="margin-left: 8px">
                  <div class="content-loading" v-if="item.status === 'init'">
                    <RotateLoading />AI正在生成回答
                  </div>
                  <div class="content-loading" v-if="item.status === 'error'">
                    <!-- Ai对话异常,请稍后再试! -->
                    {{ item.answer?.question }}
                  </div>
                  <div v-else>
                    <!-- markdown解析 -->
                    <MdPreview ref="editorRef" editorId="preview-only" :modelValue="item.answer?.question" :key="index"
                      class="maxkb-md" />
                    <OperationButton 
                      v-if="item.status === 'done' || !item.status" 
                      :item="item"
                      @on-copy="handleCopyClick(item)" 
                      @on-regeneration="handelRegeneration(item)" 
                      @on-praise="(type)=>handlePraiseClick(item, type)"
                    />
                  </div>
                  <!--停止回答按钮-->
                  <!-- <div class="content-loading" style="position: absolute;bottom: -28px;" v-if="item.status === 'pending'">
                        <span class="flex-center cursor" @click="handelAbort">
                          <img src="https://ai.datacube888.com/assets/svg/tingzhi.430d58c5.svg" alt="" style="width: 16px; margin-right: 5px;" /> 
                          停止回答
                        </span>
                      </div> -->
                </div>
              </div>
            </li>
          </ul>
          <!--Popover 弹出框 start-->
          <CreatePopover />
          <!--Popover 弹出框 end-->
        </div>
      </div>
    </el-scrollbar>
    <!--底部-->
    <div class="ai-chat-footer-box">
      <div class="ai-chat-footer flex" :class="{ 'active-focus': isFocus }">
        <div class="flex align-center">
          <!--上传文件 -->
          <el-tooltip effect="dark" content="上传文件：支持PDF/Word/PPT/txt等，最大50MB" placement="top">
            <el-upload 
              class="avatar-uploader" 
              action="/dada/base/anyone/file/upload" 
              :show-file-list="false"
              accept=".pdf,.docx,.pptx,.txt"
              :on-success="handleAvatarSuccess" 
              :before-upload="beforeAvatarUpload" 
              :headers="getHeaders()" :data="{
                bizType: 'DOC'
              }"
            >
              <lz-svg-icon icon-class="lianjie" :style="{ 'fontSize': '18px', color: '#333' }" />
            </el-upload>
          </el-tooltip>
        </div>
        <!-- 输入消息-->
        <div class="w-full">
          <div v-if="fileList.length" class="flex-wrap gap-2 p-8-12">
            <el-tag v-for="item in fileList" :key="item.path" closable type="primary" @close="handleClose(item)">
              {{ item.originalFileName }}
            </el-tag>
          </div>
          <el-input type="textarea" v-model="questionText" :rows="3" :autosize="{ minRows: 1, maxRows: 3 }"
            placeholder="请使用文字描述您的需求" resize="none" class="no-shadow" @focus="isFocus = true" @blur="isFocus = false"
            @keydown.enter.exact.prevent="handleSendMsg" @keydown.shift.enter.exact.prevent="insertNewLine" />
        </div>
        <div class="flex align-center">
          <!-- 发送消息 -->
          <div :class="['button', loading ? 'btn-loading' : '']" @click="handleSendMsg">
            <img src="@/assets/webapp/13.svg" alt="" />
          </div>
        </div>
      </div>
    </div>

  </div>
</template>

<script setup lang="ts">
import { ref, nextTick, watch } from 'vue'
import { MsgError, MsgSuccess, MsgWarning } from '@/utils/message'
import { aiChat } from '@/api/finyxbot'
import { chatResponseToText } from '@/request/fetchWithAbort'
import RotateLoading from './RotateLoading.vue'
import OperationButton from './OperationButton.vue'
import useStore from '@/stores'
import { copyClick } from '@/utils/clipboard'
import { getHeaders } from '@/request/http'
import { praise, questionAnswering, save16 } from '@/servers/finyx/api/zhinengtiduihuajilu'
import CreatePopover from './CreatePopover.vue'
import type { UploadProps } from 'element-plus'
import type { AnswerStatus } from '@/stores/modules/chat'

const { chat } = useStore()

/** 滚动 */
const scrollDiv = ref<HTMLElement | null | any>(null)
const dialogScrollbar = ref<HTMLElement | null | any>(null)
const scorll = ref(true) // 是否允许滚动
const scrollTop = ref(0) // 滚动条距离最上面的高度
const questionText = ref('')
const loading = ref(false)
const isFocus = ref(false)
const editorRef = ref<any>(null)
const fileList = ref<any[]>([])
const getParamsData = ref<any>({})

/** 获取滚动条最大高度 */
const getMaxHeight = () => {
  return dialogScrollbar.value!.scrollHeight
}

/** 停止回答 */
const handelAbort = () => {
  try {
    // @ts-ignore
    window?._controller?.abort()
    loading.value = false
    setItemStatus('done')
  } catch (err) {
    console.log(err)
  }
}
/* Shift+Enter换行 */ 
const insertNewLine = () => {
  const textarea = document.querySelector('.ai-chat-footer .el-textarea__inner') as HTMLTextAreaElement
  if (textarea) {
    const start = textarea.selectionStart
    const end = textarea.selectionEnd
    const text = questionText.value
    questionText.value = text.substring(0, start) + '\n' + text.substring(end)

    // 将光标移动到插入的换行符之后
    nextTick(() => {
      textarea.selectionStart = start + 1
      textarea.selectionEnd = start + 1
    })
  }
}

/** 上传文件-删除 */
const handleClose = (item: any) => {
  console.log(item)
  fileList.value = fileList.value.filter((i: any) => i.path !== item.path)
}


/** 上传文件-成功 */
const handleAvatarSuccess: UploadProps['onSuccess'] = (
  response
) => {
  const { originalFileName, path } = response.data;
  fileList.value.push({ originalFileName, path })
  MsgSuccess('上传成功')
}

/** 上传文件-开始 */
const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
  // 支持的文件类型
  const allowedTypes = [
    // PDF
    'application/pdf',
    // Word文档
    'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // .docx
    // PPT
    'application/vnd.ms-powerpoint', // .ppt
    'application/vnd.openxmlformats-officedocument.presentationml.presentation', // .pptx
    // 文本文件
    'text/plain', // .txt
  ];
  if (!allowedTypes.includes(rawFile.type)) {
    MsgError('仅支持PDF/Word/PPT/txt等格式');
    return false
  }
  // 检查文件大小 (50MB)
  if (rawFile.size / 1024 / 1024 > 50) {
    MsgError('最大支持50MB!');
    return false;
  }
  return true
}

/** 喜欢不喜欢 */
const handlePraiseClick = (item: any, type: any) => {
  praise({ id: item.answer.id, praise: type})
    .then(() => {
      item.praise = type
    })
    .catch((err: any) => {
      MsgError(err?.message|| '操作失败')
    })
}

/** 重新生成 */
const handelRegeneration = (item: any) => {
  console.log('重新生成', item.question)
  questionText.value = item.question
  handleSendMsg();
}

/** 复制 */
const handleCopyClick = (item: any) => {
  copyClick((item?.answer?.question || '').trim())
}

/**
* 滚动滚动条到最上面
* @param $event
*/
const handleScrollTop = ($event: any) => {
  scrollTop.value = $event.scrollTop
  if (dialogScrollbar.value.scrollHeight - (scrollTop.value + scrollDiv.value.wrapRef.offsetHeight) <= 80 ) {
    scorll.value = true
  } else {
    scorll.value = false
  }
}

/**
 * 处理跟随滚动条
 */
const handleScroll = () => {
  if (scrollDiv.value) {
    // 内部高度小于外部高度 就需要出滚动条
    if (scrollDiv.value.wrapRef.offsetHeight < dialogScrollbar.value.scrollHeight) {
      // 如果当前滚动条距离最下面的距离在 规定距离 滚动条就跟随
      if (scorll.value) {
        scrollDiv.value.setScrollTop(getMaxHeight() + 10)
      }
    }
  }
}

/** 发送消息 */
const handleSendMsg = () => {
  if (loading.value) return
  if (!questionText.value.trim()) {
    return MsgWarning('请输入您的问题')
  }

  loading.value = true

  chat.addQuestionList([{
    question: questionText.value,
    status: 'init',
    id: '',
    sessionId: chat.info.historyId,
    applicationId: chat.info.agentId,
    answer: {
      question: '',
    }
  }])

  sendMsg(questionText.value)

  nextTick(() => {
    setTimeout(() => {
      questionText.value = ''
      fileList.value = []
      scorll.value = true
      handleScroll()
    },100)
  })
}

/** 获取参数 */
const getMsgParams = async (content: string) => {
  getParamsData.value = {}
  const params: any = {
    applicationId: chat.info.agentId, // 智能体编号
    sessionId: chat.info.historyId,
    question: content,
    chatType: 'text', // 	对话类型（text/image/file）
  }
  /** 新建会话 */
  if (!chat.info.historyId) {
    await chat.createSession();
    params.sessionId = chat.info.historyId
  }
  /* 附件信息 */
  if (fileList.value.length) {
    params.chatType = 'file'
    params.files = fileList.value.map((item: any) => {
      return {
        file: item.originalFileName,
        path: item.path
      }
    })
  }

  /* 获取智能问答参数 */
  const res = await questionAnswering(params)
   /** 存储参数 */
  getParamsData.value = params
  return res
}

/** 发送对话 */
const sendMsg = async (content: string) => {
  // 新建会话
  const isNew = chat.info.historyId === ''
  const params: any = await getMsgParams(content)
  handleScroll()
  aiChat(params)
    .then((response) => {
      chatResponseToText(response, async(status, data: any, allContent: any) => {
        // console.log('status', status, 'data', data, 'allContent', allContent)
        if (status) {
          if (data.type === 'done') {
            // 对话完成
            setItemStatus('done')
            loading.value = false
            data.content && insertItemContent(data?.content || '')
            // 存储对话记录
           saveChat({
              ...getParamsData.value,
              answer: {
                question: getItemContent() || allContent,
                "applicationId": getParamsData.value.applicationId,
                "chatRole": "assistant",
                "chatType": getParamsData.value.chatType,
                "sessionId": getParamsData.value.sessionId,
              }
            }, isNew)
          } else if (data.type === 'error') {
            // 对话错误
            MsgWarning(data.error)
            setItemStatus('error')
            data.content && insertItemContent(allContent)
            loading.value = false
            handelAbort()
          } else {
            // 对话中
            data.content && insertItemContent(allContent)
            setItemStatus('pending')
          }
        } else {
          // 对话错误
          MsgWarning(data.content)
          setItemStatus('error')
          data.content && insertItemContent(allContent)
          loading.value = false
          handelAbort()
        }
        setTimeout(() => {
          handleScroll()
        }, 10)
      })
    })
    .catch((e) => {
      console.log(e)
      MsgWarning('Ai对话异常,请稍后再试!')
      loading.value = false
      setItemStatus('error')
    })
}

/* 存储对话记录 */
const saveChat = (params: any, isNew: boolean) => { 
  save16(params)
    .then((res: any) => { 
      setItemCreateAnswer(res.id, res.createdTime)
      // 刷新左侧列表
      isNew && chat.getHistoryList();
    }).catch((err) => { 
      MsgError(err.message)
    })
} 

/** caht 当前对话内容*/
const getItemContent = () => {
  const lastIndex = chat.questionList.length - 1
  if (lastIndex >= 0) {
    return chat.questionList[lastIndex].answer.question
  }
}


/** caht 插入内容*/
const insertItemContent = (content: string) => {
  const lastIndex = chat.questionList.length - 1
  if (lastIndex >= 0) {
    chat.questionList[lastIndex].answer.question = content
  }
}

/** 设置item状态 */
const setItemStatus = (status: AnswerStatus) => {
  const lastIndex = chat.questionList.length - 1
  const itemStatus = chat.questionList[lastIndex]?.status || ''
  if (lastIndex >= 0 && !['done'].includes(itemStatus)) {
    chat.questionList[lastIndex].status = status
  }
}

/** 设置对话记录的 id 时间 */
const setItemCreateAnswer = (id: any, time: string) => {
  const lastIndex = chat.questionList.length - 1
  if (lastIndex >= 0) {
    chat.questionList[lastIndex].answer.id = id
    chat.questionList[lastIndex].answer.createdTime = time
  }
}

/** 监听数据 */
watch(
  chat.questionList, 
  () => { handleScroll()},
  {
    deep: true, immediate: true
  }
)

/** 导出方法 */
defineExpose({
  handelAbort
})
</script>

<style scoped lang="scss">
.ai-chat {
  padding: 0 20px;
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 76%;
  margin: 0 auto;

  &-header {
    background-color: #fff;

    &-info {
      padding: 9px 12px;
      display: flex;
      border-radius: 8px 8px 0 0;
      background: linear-gradient(90deg, #e7eeff 0%, #daeaff 48%, #daf4ff 100%);

      .logo {
        width: 73px;
        margin-right: 7px;

        img {
          width: 100%;
        }
      }

      .info-title {
        font-weight: 500;
        font-size: 16px;
        color: #191919;
        margin-top: 7px;
        margin-bottom: 4px;
      }

      .info-sub-title {
        font-weight: 400;
        font-size: 12px;
        color: #333333;
        margin-bottom: 4px;
      }

      .info-user {
        font-size: 11px;
        color: #999999;
        display: flex;
        align-items: center;
      }
    }

    &-tips {
      border-radius: 0 0 8px 8px;
      padding: 16px;

      .title {
        font-weight: 500;
        font-size: 14px;
        color: #191919;
        line-height: 17px;
        margin-bottom: 10px;
      }

      .tag {
        padding: 5px 20px;
        background: #e8efff;
        border-radius: 4px;
        font-weight: 400;
        font-size: 12px;
        color: #6489E3;
        line-height: 14px;
        display: inline-block;
        margin: 0 8px 8px 0;
        cursor: pointer;
      }
    }
  }

  &-content {
    flex: 1;
    margin-bottom: 20px;
    padding-top: 20px;

    .question,
    .answer {
      display: flex;
      margin-bottom: 16px; // 增加一些间距
      position: relative;

      .avatar {
        margin-top: 8px;
        margin-bottom: 4px;

        img {
          width: 28px;
          height: 28px;
        }
      }

      .content-wrapper {
        flex: 1;
        padding: 12px; // 添加填充
        border-radius: 8px; // 圆角
        background-color: #E2ECFF; // 背景色
        margin-top: 4px; // 与头像的垂直间距

        .content {
          // 内容文本的样式，可以根据需要调整
          font-size: 14px;
          color: #333;
          white-space: pre-wrap;
        }

        .content-loading {
          display: flex;
          align-items: center;
        }
      }
    }

    .question {
      align-items: flex-end; // 问题左对齐

      .content-wrapper {
        width: 60%;
        margin-left: 10%;
      }
    }

    .answer {
      align-items: flex-start; // 答案右对齐
      justify-content: flex-end;

      .content-wrapper {
        margin-right: 8px; // 与头像的水平间距
        background-color: #fff // 答案使用不同的背景色以示区分;
      }
    }
  }

  &-footer {
    position: relative;
    padding: 8px 12px;
    box-shadow: 0 6px 24px #1f232914;
    background-color: #fff;
    border-radius: 8px;
    border: 1px solid #ffffff;
    box-sizing: border-box;
    transition: all .3s ease;
    margin-top: 20px;

    .button {
      width: 36px;
      height: 36px;
      background: #3067ef;
      border-radius: 8px;
      display: flex;
      align-items: center;
      justify-content: center;
      cursor: pointer;

      img {
        margin: 0 auto;
      }
    }

    .btn-loading {
      background-color: #999;
    }
  }

  &-header-tips {
    background-color: #fff;
  }

}

.ai-chat-box {
  position: relative;
}

.ai-chat-footer-box {
  position: relative;
  // margin-top: 20px;
}

.ai-chat-footer-box::after {
  background: linear-gradient(0deg, #f3f7f9 0%, rgba(243, 247, 249, 0) 100%);
  content: "";
  position: absolute;
  width: 100%;
  z-index: 1;
  top: -15px;
  left: 0;
  height: 16px;
}

.active-focus {
  border: 1px solid var(--el-color-primary);
}

</style>